From 483b0bb0966ad5898198b6345e6d0b4e3085db49 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 21:18:58 -0600 Subject: [PATCH 01/62] Consolidate Python configs to pyproject, remove unused catalog file --- .pylintrc | 163 -- .style.yapf | 3 - mypy.ini | 6 - old-catalog.json | 4186 ---------------------------------------------- pyproject.toml | 27 +- pytest.ini | 3 - 6 files changed, 26 insertions(+), 4362 deletions(-) delete mode 100644 .pylintrc delete mode 100644 .style.yapf delete mode 100644 mypy.ini delete mode 100644 old-catalog.json delete mode 100644 pytest.ini diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index eb2b9222..00000000 --- a/.pylintrc +++ /dev/null @@ -1,163 +0,0 @@ -[MASTER] - -jobs=1 -persistent=yes -suggestion-mode=yes -unsafe-load-any-extension=no - -[MESSAGES CONTROL] - -confidence= -disable = C,too-few-public-methods,redefined-outer-name, - unsubscriptable-object, - unused-import -enable=c-extension-no-member - - -[REPORTS] - -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) -output-format=colorized -reports=no -score=yes - - -[REFACTORING] - -max-nested-blocks=5 -never-returning-functions=optparse.Values,sys.exit - - -[BASIC] - -argument-naming-style=snake_case -attr-naming-style=snake_case -class-attribute-naming-style=snake_case -class-naming-style=PascalCase -const-naming-style=UPPER_CASE -docstring-min-length=-1 -function-naming-style=snake_case -# Good variable names which should always be accepted, separated by a comma -good-names=i, - j, - k, - ex, - Run, - fd, - _ - -include-naming-hint=no -inlinevar-naming-style=any -method-naming-style=snake_case -module-naming-style=snake_case -name-group= -no-docstring-rgx=^_ -variable-naming-style=snake_case - - -[FORMAT] - -expected-line-ending-format=LF -ignore-long-lines=^\s*(# )??$ -max-line-length=100 -max-module-lines=1000 -no-space-check=trailing-comma, - dict-separator -single-line-class-stmt=no -single-line-if-stmt=no - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME, - XXX, - TODO - - -[SIMILARITIES] - -ignore-comments=yes -ignore-docstrings=yes -ignore-imports=no -min-similarity-lines=4 - - -[SPELLING] - -max-spelling-suggestions=4 -spelling-dict= -spelling-ignore-words= -spelling-private-dict-file= -spelling-store-unknown-words=no - - -[TYPECHECK] - -contextmanager-decorators=contextlib.contextmanager -generated-members= -ignore-mixin-members=yes -ignore-on-opaque-inference=yes -ignored-classes=optparse.Values,thread._local,_thread._local -ignored-modules= -missing-member-hint=yes -missing-member-hint-distance=1 -missing-member-max-choices=1 - - -[VARIABLES] - -additional-builtins= -allow-global-unused-variables=yes -callbacks=cb_, - _cb -dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ -ignored-argument-names=_.*|^ignored_|^unused_ -init-import=no -redefining-builtins-modules=six.moves,past.builtins,future.builtins - - -[CLASSES] - -defining-attr-methods=__init__,__new__ - -exclude-protected=_asdict, - _fields, - _replace, - _source, - _make -valid-classmethod-first-arg=cls -valid-metaclass-classmethod-first-arg=mcs - - -[DESIGN] - -max-args=5 -max-attributes=7 -max-bool-expr=5 -max-branches=12 -max-locals=15 -max-parents=7 -max-public-methods=20 -max-returns=6 -max-statements=50 -min-public-methods=2 - - -[IMPORTS] - -allow-wildcard-with-all=no -analyse-fallback-blocks=no -deprecated-modules=optparse,tkinter.tix -ext-import-graph= -import-graph= -int-import-graph= -known-standard-library= -known-third-party=enchant diff --git a/.style.yapf b/.style.yapf deleted file mode 100644 index b4a1f688..00000000 --- a/.style.yapf +++ /dev/null @@ -1,3 +0,0 @@ -[style] -based_on_style = pep8 -column_limit = 120 \ No newline at end of file diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index 37f011b0..00000000 --- a/mypy.ini +++ /dev/null @@ -1,6 +0,0 @@ -[mypy] -strict=True -ignore_missing_imports=True -incremental=True -sqlite_cache=True -mypy_path = tools/ \ No newline at end of file diff --git a/old-catalog.json b/old-catalog.json deleted file mode 100644 index 04913f25..00000000 --- a/old-catalog.json +++ /dev/null @@ -1,4186 +0,0 @@ -{ - "packages": { - "abseil": { - "2018.6.0": { - "depends": [], - "description": "Abseil Common Libraries", - "git": { - "auto-lib": "abseil/abseil", - "ref": "20180600", - "transform": [ - { - "move": { - "exclude": [], - "from": "absl", - "include": [], - "strip-components": 0, - "to": "src/absl/" - }, - "remove": { - "only-matching": [ - "**/*_test.c*", - "**/*_testing.c*", - "**/*_benchmark.c*", - "**/benchmarks.c*", - "**/*_test_common.c*", - "**/mocking_*.c*", - "**/test_util.cc", - "**/mutex_nonprod.cc", - "**/named_generator.cc", - "**/print_hash_of.cc", - "**/*_gentables.cc" - ], - "path": "src/" - } - } - ], - "url": "https://github.com/abseil/abseil-cpp.git" - } - }, - "2019.8.8": { - "depends": [], - "description": "Abseil Common Libraries", - "git": { - "auto-lib": "abseil/abseil", - "ref": "20190808", - "transform": [ - { - "move": { - "exclude": [], - "from": "absl", - "include": [], - "strip-components": 0, - "to": "src/absl/" - }, - "remove": { - "only-matching": [ - "**/*_test.c*", - "**/*_testing.c*", - "**/*_benchmark.c*", - "**/benchmarks.c*", - "**/*_test_common.c*", - "**/mocking_*.c*", - "**/test_util.cc", - "**/mutex_nonprod.cc", - "**/named_generator.cc", - "**/print_hash_of.cc", - "**/*_gentables.cc" - ], - "path": "src/" - } - } - ], - "url": "https://github.com/abseil/abseil-cpp.git" - } - }, - "2020.2.25": { - "depends": [], - "description": "Abseil Common Libraries", - "git": { - "auto-lib": "abseil/abseil", - "ref": "20200225.2", - "transform": [ - { - "move": { - "exclude": [], - "from": "absl", - "include": [], - "strip-components": 0, - "to": "src/absl/" - }, - "remove": { - "only-matching": [ - "**/*_test.c*", - "**/*_testing.c*", - "**/*_benchmark.c*", - "**/benchmarks.c*", - "**/*_test_common.c*", - "**/mocking_*.c*", - "**/test_util.cc", - "**/mutex_nonprod.cc", - "**/named_generator.cc", - "**/print_hash_of.cc", - "**/*_gentables.cc" - ], - "path": "src/" - } - } - ], - "url": "https://github.com/abseil/abseil-cpp.git" - } - } - }, - "asio": { - "1.12.0": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-12-0", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.12.1": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-12-1", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.12.2": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-12-2", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.13.0": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-13-0", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.14.0": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-14-0", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.14.1": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-14-1", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.16.0": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-16-0", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - }, - "1.16.1": { - "depends": [], - "description": "Asio asynchronous I/O C++ library", - "git": { - "auto-lib": "asio/asio", - "ref": "asio-1-16-1", - "transform": [ - { - "move": { - "exclude": [], - "from": "asio/src", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [ - "doc/**", - "examples/**", - "tests/**", - "tools/**" - ], - "path": "src/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define ASIO_STANDALONE 1", - "kind": "insert", - "line": 13 - }, - { - "content": "#define ASIO_SEPARATE_COMPILATION 1", - "kind": "insert", - "line": 14 - } - ], - "path": "include/asio/detail/config.hpp" - }, - "move": { - "exclude": [], - "from": "asio/include/", - "include": [], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/chriskohlhoff/asio.git" - } - } - }, - "boost.leaf": { - "0.1.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.1.0", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.2.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.2.0", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.2.1": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.2.1", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.2.2": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.2.2", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.2.3": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.2.3", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.2.4": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.2.4", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.2.5": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.2.5", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - }, - "0.3.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/leaf", - "ref": "0.3.0", - "transform": [], - "url": "https://github.com/zajo/leaf.git" - } - } - }, - "boost.mp11": { - "1.70.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/mp11", - "ref": "boost-1.70.0", - "transform": [], - "url": "https://github.com/boostorg/mp11.git" - } - }, - "1.71.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/mp11", - "ref": "boost-1.71.0", - "transform": [], - "url": "https://github.com/boostorg/mp11.git" - } - }, - "1.72.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/mp11", - "ref": "boost-1.72.0", - "transform": [], - "url": "https://github.com/boostorg/mp11.git" - } - }, - "1.73.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/mp11", - "ref": "boost-1.73.0", - "transform": [], - "url": "https://github.com/boostorg/mp11.git" - } - } - }, - "boost.pfr": { - "1.0.0": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/pfr", - "ref": "1.0.0", - "transform": [], - "url": "https://github.com/apolukhin/magic_get.git" - } - }, - "1.0.1": { - "depends": [], - "description": "(No description was provided)", - "git": { - "auto-lib": "boost/pfr", - "ref": "1.0.1", - "transform": [], - "url": "https://github.com/apolukhin/magic_get.git" - } - } - }, - "catch2": { - "2.12.4": { - "depends": [], - "description": "A modern C++ unit testing library", - "git": { - "auto-lib": "catch2/catch2", - "ref": "v2.12.4", - "transform": [ - { - "move": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 0, - "to": "include/catch2" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 0, - "to": "src" - }, - "write": { - "content": "\n #pragma once\n\n #define CATCH_CONFIG_MAIN\n #include \"./catch.hpp\"\n\n namespace Catch {\n\n CATCH_REGISTER_REPORTER(\"console\", ConsoleReporter)\n\n }\n ", - "path": "include/catch2/catch_with_main.hpp" - } - } - ], - "url": "https://github.com/catchorg/Catch2.git" - } - } - }, - "cereal": { - "0.9.0": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v0.9.0", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "0.9.1": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v0.9.1", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.0.0": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.0.0", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.1.0": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.1.0", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.1.1": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.1.1", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.1.2": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.1.2", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.2.0": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.2.0", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.2.1": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.2.1", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.2.2": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.2.2", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - }, - "1.3.0": { - "depends": [], - "description": "A C++11 library for serialization", - "git": { - "auto-lib": "cereal/cereal", - "ref": "v1.3.0", - "transform": [], - "url": "https://github.com/USCiLab/cereal.git" - } - } - }, - "ctre": { - "2.8.1": { - "depends": [], - "description": "A compile-time PCRE (almost) compatible regular expression matcher", - "git": { - "auto-lib": "hanickadot/ctre", - "ref": "v2.8.1", - "transform": [], - "url": "https://github.com/hanickadot/compile-time-regular-expressions.git" - } - }, - "2.8.2": { - "depends": [], - "description": "A compile-time PCRE (almost) compatible regular expression matcher", - "git": { - "auto-lib": "hanickadot/ctre", - "ref": "v2.8.2", - "transform": [], - "url": "https://github.com/hanickadot/compile-time-regular-expressions.git" - } - }, - "2.8.3": { - "depends": [], - "description": "A compile-time PCRE (almost) compatible regular expression matcher", - "git": { - "auto-lib": "hanickadot/ctre", - "ref": "v2.8.3", - "transform": [], - "url": "https://github.com/hanickadot/compile-time-regular-expressions.git" - } - }, - "2.8.4": { - "depends": [], - "description": "A compile-time PCRE (almost) compatible regular expression matcher", - "git": { - "auto-lib": "hanickadot/ctre", - "ref": "v2.8.4", - "transform": [], - "url": "https://github.com/hanickadot/compile-time-regular-expressions.git" - } - } - }, - "fmt": { - "6.0.0": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "6.0.0", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "6.1.0": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "6.1.0", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "6.1.1": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "6.1.1", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "6.1.2": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "6.1.2", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "6.2.0": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "6.2.0", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "6.2.1": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "6.2.1", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "7.0.0": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "7.0.0", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "7.0.1": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "7.0.1", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "7.0.2": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "7.0.2", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - }, - "7.0.3": { - "depends": [], - "description": "A modern formatting library : https://fmt.dev/", - "git": { - "auto-lib": "fmt/fmt", - "ref": "7.0.3", - "transform": [], - "url": "https://github.com/fmtlib/fmt.git" - } - } - }, - "hinnant-date": { - "2.4.1": { - "depends": [], - "description": "A date and time library based on the C++11/14/17 header", - "git": { - "auto-lib": "hinnant/date", - "ref": "v2.4.1", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/HowardHinnant/date.git" - } - }, - "3.0.0": { - "depends": [], - "description": "A date and time library based on the C++11/14/17 header", - "git": { - "auto-lib": "hinnant/date", - "ref": "v3.0.0", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/HowardHinnant/date.git" - } - } - }, - "inja": { - "1.0.0": { - "depends": [], - "description": "A Template Engine for Modern C++", - "git": { - "auto-lib": "inja/inja", - "ref": "v1.0.0", - "transform": [], - "url": "https://github.com/pantor/inja.git" - } - }, - "2.0.0": { - "depends": [], - "description": "A Template Engine for Modern C++", - "git": { - "auto-lib": "inja/inja", - "ref": "v2.0.0", - "transform": [], - "url": "https://github.com/pantor/inja.git" - } - }, - "2.0.1": { - "depends": [], - "description": "A Template Engine for Modern C++", - "git": { - "auto-lib": "inja/inja", - "ref": "v2.0.1", - "transform": [], - "url": "https://github.com/pantor/inja.git" - } - }, - "2.1.0": { - "depends": [ - "nlohmann-json+0.0.0" - ], - "description": "A Template Engine for Modern C++", - "git": { - "ref": "v2.1.0", - "transform": [ - { - "write": { - "content": "{\"name\": \"inja\", \"namespace\": \"inja\", \"version\": \"2.1.0\", \"depends\": [\"nlohmann-json+0.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"inja\", \"uses\": [\"nlohmann/json\"]}", - "path": "library.json" - } - } - ], - "url": "https://github.com/pantor/inja.git" - } - }, - "2.2.0": { - "depends": [ - "nlohmann-json+0.0.0" - ], - "description": "A Template Engine for Modern C++", - "git": { - "ref": "v2.2.0", - "transform": [ - { - "write": { - "content": "{\"name\": \"inja\", \"namespace\": \"inja\", \"version\": \"2.2.0\", \"depends\": [\"nlohmann-json+0.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"inja\", \"uses\": [\"nlohmann/json\"]}", - "path": "library.json" - } - } - ], - "url": "https://github.com/pantor/inja.git" - } - } - }, - "libsodium": { - "1.0.10": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.10", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.11": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.11", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.12": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.12", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.13": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.13", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.14": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.14", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.15": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.15", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.16": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.16", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.17": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.17", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - }, - "1.0.18": { - "depends": [], - "description": "Sodium is a new, easy-to-use software library for encryption,\ndecryption, signatures, password hashing and more.", - "git": { - "auto-lib": "sodium/sodium", - "ref": "1.0.18", - "transform": [ - { - "edit": { - "edits": [ - { - "content": "#define SODIUM_STATIC 1", - "kind": "insert", - "line": 8 - } - ], - "path": "include/sodium/export.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium/include", - "include": [], - "strip-components": 0, - "to": "include/" - } - }, - { - "edit": { - "edits": [ - { - "content": "#pragma once\n\n// clang-format off\n\n/**\n * Header checks\n */\n#if __has_include()\n #define HAVE_SYS_MMAN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_RANDOM_H 1\n#endif\n\n#if __has_include()\n #define HAVE_INTRIN_H 1\n#endif\n\n#if __has_include()\n #define HAVE_SYS_AUXV_H 1\n#endif\n\n/**\n * Architectural checks for intrinsics\n */\n#if __has_include() && __MMX__\n #define HAVE_MMINTRIN_H 1\n#endif\n\n#if __has_include() && __SSE2__\n #define HAVE_EMMINTRIN_H 1\n#endif\n\n#if __SSE3__\n #if __has_include()\n #define HAVE_PMMINTRIN_H 1\n #endif\n #if __has_include()\n #define HAVE_TMMINTRIN_H 1\n #endif\n#endif\n\n#if __has_include() && __SSE4_1__\n #define HAVE_SMMINTRIN_H\n#endif\n\n#if __has_include()\n #if __AVX__\n #define HAVE_AVXINTRIN_H\n #endif\n #if __AVX2__\n #define HAVE_AVX2INTRIN_H\n #endif\n #if __AVX512F__\n #if defined(__clang__) && __clang_major__ < 4\n // AVX512 may be broken\n #elif defined(__GNUC__) && __GNUC__ < 6\n // ''\n #else\n #define HAVE_AVX512FINTRIN_H\n #endif\n #endif\n#endif\n\n#if __has_include() && __AES__\n #define HAVE_WMMINTRIN_H 1\n#endif\n\n#if __RDRND__\n #define HAVE_RDRAND\n#endif\n\n/**\n * Detect mman APIs\n */\n#if __has_include()\n #define HAVE_MMAP 1\n #define HAVE_MPROTECT 1\n #define HAVE_MLOCK 1\n\n #if defined(_DEFAULT_SOURCE) || defined(_BSD_SOURCE)\n #define HAVE_MADVISE 1\n #endif\n#endif\n\n#if __has_include()\n #define HAVE_GETRANDOM 1\n#endif\n\n/**\n * POSIX-Only stuff\n */\n#if __has_include()\n #if defined(_DEFAULT_SOURCE)\n #define HAVE_GETENTROPY 1\n #endif\n\n /**\n * Default POSIX APIs\n */\n #define HAVE_POSIX_MEMALIGN 1\n #define HAVE_GETPID 1\n #define HAVE_NANOSLEEP 1\n\n /**\n * Language/library features from C11\n */\n #if __STDC_VERSION__ >= 201112L\n #define HAVE_MEMSET_S 1\n #endif\n\n #if __linux__\n #define HAVE_EXPLICIT_BZERO 1\n #endif\n#endif\n\n/**\n * Miscellaneous\n */\n#if __has_include()\n #define HAVE_PTHREAD 1\n#endif\n\n#if __has_include()\n #include \n #if __BYTE_ORDER == __BIG_ENDIAN\n #define NATIVE_BIG_ENDIAN 1\n #elif __BYTE_ORDER == __LITTLE_ENDIAN\n #define NATIVE_LITTLE_ENDIAN 1\n #else\n #error \"Unknown endianness for this platform.\"\n #endif\n#elif defined(_MSVC)\n // At time of writing, MSVC only targets little-endian.\n #define NATIVE_LITTLE_ENDIAN 1\n#else\n #error \"Unknown endianness for this platform.\"\n#endif\n\n#define CONFIGURED 1\n", - "kind": "insert", - "line": 1 - } - ], - "path": "include/sodium/private/common.h" - } - }, - { - "copy": { - "exclude": [], - "from": "builds/msvc/version.h", - "include": [], - "strip-components": 0, - "to": "include/sodium/version.h" - }, - "move": { - "exclude": [], - "from": "src/libsodium", - "include": [], - "strip-components": 0, - "to": "src/" - }, - "remove": { - "only-matching": [], - "path": "src/libsodium" - } - }, - { - "copy": { - "exclude": [], - "from": "include", - "include": [], - "strip-components": 1, - "to": "src/" - } - } - ], - "url": "https://github.com/jedisct1/libsodium.git" - } - } - }, - "lua": { - "5.1.1": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.1.1", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.2.0": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.2.0", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.2.1": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.2.1", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.2.2": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.2.2", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.2.3": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.2.3", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.3.0": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.3.0", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.3.1": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.3.1", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.3.2": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.3.2", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.3.3": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.3.3", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.3.4": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.3.4", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.3.5": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.3.5", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - }, - "5.4.0": { - "depends": [], - "description": "Lua is a powerful and fast programming language that is easy to learn and use and to embed into your application.", - "git": { - "auto-lib": "lua/lua", - "ref": "v5.4.0", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - } - ], - "url": "https://github.com/lua/lua.git" - } - } - }, - "magic_enum": { - "0.5.0": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.5.0", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.0": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.0", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.1": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.1", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.2": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.2", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.3": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.3", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.4": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.4", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.5": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.5", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - }, - "0.6.6": { - "depends": [], - "description": "Static reflection for enums", - "git": { - "auto-lib": "neargye/magic_enum", - "ref": "v0.6.6", - "transform": [], - "url": "https://github.com/Neargye/magic_enum.git" - } - } - }, - "ms-wil": { - "2020.03.16": { - "depends": [], - "description": "The Windows Implementation Library", - "git": { - "ref": "dds/2020.03.16", - "transform": [], - "url": "https://github.com/vector-of-bool/wil.git" - } - } - }, - "nameof": { - "0.8.3": { - "depends": [], - "description": "Nameof operator for modern C++", - "git": { - "auto-lib": "neargye/nameof", - "ref": "v0.8.3", - "transform": [], - "url": "https://github.com/Neargye/nameof.git" - } - }, - "0.9.0": { - "depends": [], - "description": "Nameof operator for modern C++", - "git": { - "auto-lib": "neargye/nameof", - "ref": "v0.9.0", - "transform": [], - "url": "https://github.com/Neargye/nameof.git" - } - }, - "0.9.1": { - "depends": [], - "description": "Nameof operator for modern C++", - "git": { - "auto-lib": "neargye/nameof", - "ref": "v0.9.1", - "transform": [], - "url": "https://github.com/Neargye/nameof.git" - } - }, - "0.9.2": { - "depends": [], - "description": "Nameof operator for modern C++", - "git": { - "auto-lib": "neargye/nameof", - "ref": "v0.9.2", - "transform": [], - "url": "https://github.com/Neargye/nameof.git" - } - }, - "0.9.3": { - "depends": [], - "description": "Nameof operator for modern C++", - "git": { - "auto-lib": "neargye/nameof", - "ref": "v0.9.3", - "transform": [], - "url": "https://github.com/Neargye/nameof.git" - } - }, - "0.9.4": { - "depends": [], - "description": "Nameof operator for modern C++", - "git": { - "auto-lib": "neargye/nameof", - "ref": "v0.9.4", - "transform": [], - "url": "https://github.com/Neargye/nameof.git" - } - } - }, - "neo-buffer": { - "0.2.1": { - "depends": [ - "neo-concepts^0.2.2", - "neo-fun^0.1.1" - ], - "description": "Buffer and byte algorithms/types based on those of Asio", - "git": { - "ref": "0.2.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-buffer.git" - } - }, - "0.3.0": { - "depends": [ - "neo-concepts^0.3.2", - "neo-fun^0.4.0" - ], - "description": "Buffer and byte algorithms/types based on those of Asio", - "git": { - "ref": "0.3.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-buffer.git" - } - }, - "0.4.0": { - "depends": [ - "neo-concepts^0.4.0", - "neo-fun^0.4.1" - ], - "description": "Buffer and byte algorithms/types based on those of Asio", - "git": { - "ref": "0.4.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-buffer.git" - } - }, - "0.4.1": { - "depends": [ - "neo-concepts^0.4.0", - "neo-fun^0.4.1" - ], - "description": "Buffer and byte algorithms/types based on those of Asio", - "git": { - "ref": "0.4.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-buffer.git" - } - }, - "0.4.2": { - "depends": [ - "neo-concepts^0.4.0", - "neo-fun^0.4.1" - ], - "description": "Buffer and byte algorithms/types based on those of Asio", - "git": { - "ref": "0.4.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-buffer.git" - } - } - }, - "neo-compress": { - "0.1.0": { - "depends": [ - "neo-buffer^0.4.1", - "neo-fun^0.4.0", - "zlib^1.2.9" - ], - "description": "Compression, archiving, etc. for C++20", - "git": { - "ref": "0.1.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-compress.git" - } - }, - "0.1.1": { - "depends": [ - "neo-buffer^0.4.1", - "neo-fun^0.5.0", - "zlib^1.2.9" - ], - "description": "Compression, archiving, etc. for C++20", - "git": { - "ref": "0.1.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-compress.git" - } - }, - "0.2.0": { - "depends": [ - "neo-buffer^0.4.1", - "neo-fun^0.5.0", - "zlib^1.2.9" - ], - "description": "Compression, archiving, etc. for C++20", - "git": { - "ref": "0.2.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-compress.git" - } - } - }, - "neo-concepts": { - "0.2.2": { - "depends": [], - "description": "A (mostly) backport of C++20 concepts library, with some additions.", - "git": { - "ref": "0.2.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-concepts.git" - } - }, - "0.3.0": { - "depends": [], - "description": "A (mostly) backport of C++20 concepts library, with some additions.", - "git": { - "ref": "0.3.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-concepts.git" - } - }, - "0.3.1": { - "depends": [], - "description": "A (mostly) backport of C++20 concepts library, with some additions.", - "git": { - "ref": "0.3.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-concepts.git" - } - }, - "0.3.2": { - "depends": [], - "description": "A (mostly) backport of C++20 concepts library, with some additions.", - "git": { - "ref": "0.3.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-concepts.git" - } - }, - "0.4.0": { - "depends": [], - "description": "A (mostly) backport of C++20 concepts library, with some additions.", - "git": { - "ref": "0.4.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-concepts.git" - } - } - }, - "neo-fun": { - "0.1.1": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.1.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.2.0": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.2.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.2.1": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.2.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.3.0": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.3.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.3.1": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.3.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.3.2": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.3.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.4.0": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.4.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.4.1": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.4.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.4.2": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.4.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.5.0": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.5.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.5.1": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.5.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.5.2": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.5.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.5.3": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.5.3", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.5.4": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.5.4", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.5.5": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.5.5", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - }, - "0.6.0": { - "depends": [], - "description": "Some library components that didn't quite fit anywhere else...", - "git": { - "ref": "0.6.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-fun.git" - } - } - }, - "neo-http": { - "0.1.0": { - "depends": [ - "neo-buffer^0.4.2", - "neo-fun^0.5.4" - ], - "description": "A modern HTTP library", - "git": { - "ref": "0.1.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-http.git" - } - } - }, - "neo-io": { - "0.1.0": { - "depends": [ - "neo-fun~0.5.4", - "neo-buffer~0.4.2" - ], - "description": "A modern IO library", - "git": { - "ref": "0.1.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-io.git" - } - }, - "0.1.1": { - "depends": [ - "neo-fun^0.6.0", - "neo-buffer^0.4.2" - ], - "description": "A modern IO library", - "git": { - "ref": "0.1.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-io.git" - } - } - }, - "neo-sqlite3": { - "0.2.3": { - "depends": [], - "description": "A modern and low-level C++ SQLite API", - "git": { - "ref": "0.2.3", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-sqlite3.git" - } - }, - "0.3.0": { - "depends": [], - "description": "A modern and low-level C++ SQLite API", - "git": { - "ref": "0.3.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-sqlite3.git" - } - }, - "0.4.0": { - "depends": [ - "neo-fun^0.5.0" - ], - "description": "A modern and low-level C++ SQLite API", - "git": { - "ref": "0.4.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-sqlite3.git" - } - }, - "0.4.1": { - "depends": [ - "neo-fun^0.5.0" - ], - "description": "A modern and low-level C++ SQLite API", - "git": { - "ref": "0.4.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-sqlite3.git" - } - } - }, - "neo-url": { - "0.1.0": { - "depends": [ - "neo-fun^0.4.1" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.1.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - }, - "0.1.1": { - "depends": [ - "neo-fun^0.4.3" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.1.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - }, - "0.1.2": { - "depends": [ - "neo-fun^0.4.3" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.1.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - }, - "0.2.0": { - "depends": [ - "neo-fun^0.5.5" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.2.0", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - }, - "0.2.1": { - "depends": [ - "neo-fun^0.5.5" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.2.1", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - }, - "0.2.2": { - "depends": [ - "neo-fun^0.5.5" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.2.2", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - }, - "0.2.3": { - "depends": [ - "neo-fun^0.5.5" - ], - "description": "URL parsing and handling library.", - "git": { - "ref": "0.2.3", - "transform": [], - "url": "https://github.com/vector-of-bool/neo-url.git" - } - } - }, - "nlohmann-json": { - "3.7.1": { - "depends": [], - "description": "JSON for Modern C++", - "git": { - "ref": "dds/3.7.1", - "transform": [], - "url": "https://github.com/vector-of-bool/json.git" - } - } - }, - "pcg-cpp": { - "0.98.1": { - "depends": [], - "description": "PCG Randum Number Generation, C++ Edition", - "git": { - "auto-lib": "pcg/pcg-cpp", - "ref": "v0.98.1", - "transform": [], - "url": "https://github.com/imneme/pcg-cpp.git" - } - } - }, - "pegtl": { - "2.6.0": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.6.0", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.6.1": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.6.1", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.7.0": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.7.0", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.7.1": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.7.1", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.8.0": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.8.0", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.8.1": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.8.1", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.8.2": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.8.2", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - }, - "2.8.3": { - "depends": [], - "description": "Parsing Expression Grammar Template Library", - "git": { - "auto-lib": "tao/pegtl", - "ref": "2.8.3", - "transform": [ - { - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/taocpp/PEGTL.git" - } - } - }, - "pubgrub": { - "0.2.1": { - "depends": [], - "description": "Pubgrub dependency resolution algorithm for C++", - "git": { - "ref": "0.2.1", - "transform": [], - "url": "https://github.com/vector-of-bool/pubgrub.git" - } - } - }, - "pybind11": { - "2.0.0": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.0.0", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.0.1": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.0.1", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.1.0": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.1.0", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.1.1": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.1.1", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.2.0": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.2.0", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.2.1": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.2.1", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.2.2": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.2.2", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.2.3": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.2.3", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.2.4": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.2.4", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.3.0": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.3.0", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.4.0": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.4.0", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.4.1": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.4.1", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.4.2": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.4.2", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.4.3": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.4.3", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - }, - "2.5.0": { - "depends": [], - "description": "Seamless operability between C++11 and Python", - "git": { - "auto-lib": "pybind/pybind11", - "ref": "v2.5.0", - "transform": [], - "url": "https://github.com/pybind/pybind11.git" - } - } - }, - "range-v3": { - "0.10.0": { - "depends": [], - "description": "Range library for C++14/17/20, basis for C++20's std::ranges", - "git": { - "auto-lib": "range-v3/range-v3", - "ref": "0.10.0", - "transform": [], - "url": "https://github.com/ericniebler/range-v3.git" - } - }, - "0.11.0": { - "depends": [], - "description": "Range library for C++14/17/20, basis for C++20's std::ranges", - "git": { - "auto-lib": "range-v3/range-v3", - "ref": "0.11.0", - "transform": [], - "url": "https://github.com/ericniebler/range-v3.git" - } - }, - "0.5.0": { - "depends": [], - "description": "Range library for C++14/17/20, basis for C++20's std::ranges", - "git": { - "auto-lib": "range-v3/range-v3", - "ref": "0.5.0", - "transform": [], - "url": "https://github.com/ericniebler/range-v3.git" - } - }, - "0.9.0": { - "depends": [], - "description": "Range library for C++14/17/20, basis for C++20's std::ranges", - "git": { - "auto-lib": "range-v3/range-v3", - "ref": "0.9.0", - "transform": [], - "url": "https://github.com/ericniebler/range-v3.git" - } - }, - "0.9.1": { - "depends": [], - "description": "Range library for C++14/17/20, basis for C++20's std::ranges", - "git": { - "auto-lib": "range-v3/range-v3", - "ref": "0.9.1", - "transform": [], - "url": "https://github.com/ericniebler/range-v3.git" - } - } - }, - "semver": { - "0.2.2": { - "depends": [], - "description": "A C++ Library for Dealing with Semantic Versioning", - "git": { - "ref": "0.2.2", - "transform": [], - "url": "https://github.com/vector-of-bool/semver.git" - } - } - }, - "sol2": { - "2.20.0": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.0", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.0\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "2.20.1": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.1", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.1\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "2.20.2": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.2", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.2\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "2.20.3": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.3", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.3\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "2.20.4": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.4", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.4\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "2.20.5": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.5", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.5\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "2.20.6": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v2.20.6", - "transform": [ - { - "move": { - "exclude": [], - "from": "sol", - "include": [], - "strip-components": 0, - "to": "src/sol" - }, - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"2.20.6\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "3.0.2": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v3.0.2", - "transform": [ - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"3.0.2\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "3.0.3": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v3.0.3", - "transform": [ - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"3.0.3\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "3.2.0": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v3.2.0", - "transform": [ - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"3.2.0\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - }, - "3.2.1": { - "depends": [ - "lua+0.0.0" - ], - "description": "A C++ <-> Lua API wrapper with advanced features and top notch performance", - "git": { - "ref": "v3.2.1", - "transform": [ - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"namespace\": \"sol2\",\n \"version\": \"3.2.1\",\n \"depends\": [\n \"lua+0.0.0\"\n ]\n}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\n \"name\": \"sol2\",\n \"uses\": [\n \"lua/lua\"\n ]\n}", - "path": "library.json" - } - } - ], - "url": "https://github.com/ThePhD/sol2.git" - } - } - }, - "spdlog": { - "1.4.0": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.4.0", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.4.0\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - }, - "1.4.1": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.4.1", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.4.1\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - }, - "1.4.2": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.4.2", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.4.2\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - }, - "1.5.0": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.5.0", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.5.0\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - }, - "1.6.0": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.6.0", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.6.0\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - }, - "1.6.1": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.6.1", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.6.1\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - }, - "1.7.0": { - "depends": [ - "fmt+6.0.0" - ], - "description": "Fast C++ logging library", - "git": { - "ref": "v1.7.0", - "transform": [ - { - "write": { - "content": "{\"name\": \"spdlog\", \"namespace\": \"spdlog\", \"version\": \"1.7.0\", \"depends\": [\"fmt+6.0.0\"]}", - "path": "package.json" - } - }, - { - "write": { - "content": "{\"name\": \"spdlog\", \"uses\": [\"fmt/fmt\"]}", - "path": "library.json" - } - }, - { - "edit": { - "edits": [ - { - "content": "#define SPDLOG_FMT_EXTERNAL 1", - "kind": "insert", - "line": 13 - } - ], - "path": "include/spdlog/tweakme.h" - }, - "remove": { - "only-matching": [], - "path": "src/" - } - } - ], - "url": "https://github.com/gabime/spdlog.git" - } - } - }, - "tomlpp": { - "1.0.0": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.0.0", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.1.0": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.1.0", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.2.0": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.2.0", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.2.3": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.2.3", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.2.4": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.2.4", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.2.5": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.2.5", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.3.0": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.3.0", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "1.3.3": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v1.3.3", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - }, - "2.0.0": { - "depends": [], - "description": "Header-only TOML config file parser and serializer for modern C++", - "git": { - "auto-lib": "tomlpp/tomlpp", - "ref": "v2.0.0", - "transform": [], - "url": "https://github.com/marzer/tomlplusplus.git" - } - } - }, - "vob-json5": { - "0.1.5": { - "depends": [], - "description": "A json5 library for C++", - "git": { - "ref": "0.1.5", - "transform": [], - "url": "https://github.com/vector-of-bool/json5.git" - } - } - }, - "vob-semester": { - "0.1.0": { - "depends": [ - "neo-fun^0.1.0", - "neo-concepts^0.2.1" - ], - "description": "A generic library for dealing with semistructured data", - "git": { - "ref": "0.1.0", - "transform": [], - "url": "https://github.com/vector-of-bool/semester.git" - } - }, - "0.1.1": { - "depends": [ - "neo-fun^0.1.1", - "neo-concepts^0.2.2" - ], - "description": "A generic library for dealing with semistructured data", - "git": { - "ref": "0.1.1", - "transform": [], - "url": "https://github.com/vector-of-bool/semester.git" - } - }, - "0.2.0": { - "depends": [ - "neo-fun^0.3.2", - "neo-concepts^0.3.2" - ], - "description": "A generic library for dealing with semistructured data", - "git": { - "ref": "0.2.0", - "transform": [], - "url": "https://github.com/vector-of-bool/semester.git" - } - }, - "0.2.1": { - "depends": [ - "neo-fun^0.3.2", - "neo-concepts^0.3.2" - ], - "description": "A generic library for dealing with semistructured data", - "git": { - "ref": "0.2.1", - "transform": [], - "url": "https://github.com/vector-of-bool/semester.git" - } - }, - "0.2.2": { - "depends": [ - "neo-fun^0.3.2", - "neo-concepts^0.3.2" - ], - "description": "A generic library for dealing with semistructured data", - "git": { - "ref": "0.2.2", - "transform": [], - "url": "https://github.com/vector-of-bool/semester.git" - } - } - }, - "zlib": { - "1.2.0": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.0.8", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.1": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.1.2", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.10": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.10", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.11": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.11", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.2": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.2.4", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.3": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.3.8", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.4": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.4.5", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.5": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.5.3", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.6": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.6.1", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.7": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.7.3", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.8": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.8", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - }, - "1.2.9": { - "depends": [], - "description": "A massively spiffy yet delicately unobtrusive compression library", - "git": { - "auto-lib": "zlib/zlib", - "ref": "v1.2.9", - "transform": [ - { - "move": { - "exclude": [], - "from": ".", - "include": [ - "*.c", - "*.h" - ], - "strip-components": 0, - "to": "src/" - } - }, - { - "move": { - "exclude": [], - "from": "src/", - "include": [ - "zlib.h", - "zconf.h" - ], - "strip-components": 0, - "to": "include/" - } - } - ], - "url": "https://github.com/madler/zlib.git" - } - } - } - }, - "version": 1 -} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 67c7d07e..75eddd22 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,4 +50,29 @@ reportMissingTypeStubs = false reportMissingImports = true [tool.doc8] -max_line_length = 81 \ No newline at end of file +max_line_length = 81 + +[tool.pytest.ini_options] +junit_log_passing_tests = true +junit_logging = "all" +testpaths = [ + "tests/" +] + +[tool.yapf] +based_on_style = "pep8" +column_limit = 120 + +[tool.pylint.MASTER] +jobs = 10 +persistent = true +disable = [ + "C", + "too-few-public-methods", + "redefined-outer-name", +] + +[tool.pylint.REPORTS] +reports = false +score = true +output-format = "colorized" diff --git a/pytest.ini b/pytest.ini deleted file mode 100644 index f7022212..00000000 --- a/pytest.ini +++ /dev/null @@ -1,3 +0,0 @@ -[pytest] -junit_log_passing_tests=true -junit_logging=all From 4e3894fbf21bce4485f7860210339434e6513b7a Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 21:19:44 -0600 Subject: [PATCH 02/62] Better enum normalization in debate --- src/debate/argument.hpp | 6 +++++- src/debate/argument_parser.test.cpp | 2 +- src/debate/enum.hpp | 30 ++++++++++++++++------------- 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/debate/argument.hpp b/src/debate/argument.hpp index 9696e8e8..b3c64916 100644 --- a/src/debate/argument.hpp +++ b/src/debate/argument.hpp @@ -4,6 +4,10 @@ #include +#if __has_include() +#include "./enum.hpp" +#endif + #include #include #include @@ -48,7 +52,7 @@ class integer_putter { template constexpr auto make_argument_putter(T& dest) { if constexpr (std::is_enum_v) { - return make_enum_putter(dest); /// !! README: Include to use enums here + return make_enum_putter(dest); } else if constexpr (std::is_integral_v) { return integer_putter(dest); } else { diff --git a/src/debate/argument_parser.test.cpp b/src/debate/argument_parser.test.cpp index 5624878a..8044f779 100644 --- a/src/debate/argument_parser.test.cpp +++ b/src/debate/argument_parser.test.cpp @@ -6,7 +6,7 @@ TEST_CASE("Create an argument parser") { enum log_level { - _invalid, + invalid_, info, warning, error, diff --git a/src/debate/enum.hpp b/src/debate/enum.hpp index b0b95c21..7f8ec6bc 100644 --- a/src/debate/enum.hpp +++ b/src/debate/enum.hpp @@ -8,6 +8,7 @@ #include #include +#include #include namespace debate { @@ -16,29 +17,32 @@ template class enum_putter { E* _dest; + static std::string _kebab_name(std::string val_ident) { + std::ranges::replace(val_ident, '_', '-'); + auto trim_pos = val_ident.find_last_not_of("-"); + if (trim_pos != std::string::npos) { + val_ident.erase(trim_pos + 1); + } + return val_ident; + } + public: constexpr explicit enum_putter(E& e) : _dest(&e) {} void operator()(std::string_view given, std::string_view full_arg) const { - std::optional normalized_str; - std::string_view normalized_view = given; - if (given.find('-') != given.npos) { - // We should normalize it - normalized_str.emplace(given); - for (char& c : *normalized_str) { - c = c == '-' ? '_' : c; - } - normalized_view = *normalized_str; - } - auto val = magic_enum::enum_cast(normalized_view); - if (!val) { + auto entries = magic_enum::enum_entries(); + auto matching = std::ranges::find(entries, given, [](auto&& p) { + return _kebab_name(std::string(p.second)); + }); + if (matching == std::ranges::end(entries)) { throw boost::leaf:: exception(invalid_arguments("Invalid argument value given for enum-bound argument"), e_invalid_arg_value{std::string(given)}, e_arg_spelling{std::string(full_arg)}); } - *_dest = *val; + + *_dest = matching->first; } }; From 5f0f5212f1ae3616870a92549328f59d4adb0b26 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 21:20:37 -0600 Subject: [PATCH 03/62] Use ::value for e-object members --- src/bpt.main.cpp | 48 ++++++++++++++--------------- src/debate/argument_parser.test.cpp | 13 ++++---- src/debate/error.hpp | 12 ++++---- 3 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/bpt.main.cpp b/src/bpt.main.cpp index df9122c8..c4bbe4e5 100644 --- a/src/bpt.main.cpp +++ b/src/bpt.main.cpp @@ -52,27 +52,25 @@ int main_fn(std::string_view program_name, const std::vector& argv) return std::nullopt; }, [&](debate::help_request, debate::e_argument_parser p) { - std::cout << p.parser.help_string(program_name); + std::cout << p.value.help_string(program_name); return 0; }, [&](debate::unrecognized_argument, debate::e_argument_parser p, debate::e_arg_spelling arg, debate::e_did_you_mean* dym) { - std::cerr << p.parser.usage_string(program_name) << '\n'; - if (p.parser.subparsers()) { + std::cerr << p.value.usage_string(program_name) << '\n'; + if (p.value.subparsers()) { fmt::print(std::cerr, "Unrecognized argument/subcommand: \".bold.red[{}]\"\n"_styled, - arg.spelling); + arg.value); } else { fmt::print(std::cerr, "Unrecognized argument: \".bold.red[{}]\"\n"_styled, - arg.spelling); + arg.value); } if (dym) { - fmt::print(std::cerr, - " (Did you mean '.br.yellow[{}]'?)\n"_styled, - dym->candidate); + fmt::print(std::cerr, " (Did you mean '.br.yellow[{}]'?)\n"_styled, dym->value); } return 2; }, @@ -81,12 +79,12 @@ int main_fn(std::string_view program_name, const std::vector& argv) debate::e_argument_parser p, debate::e_arg_spelling spell, debate::e_invalid_arg_value val) { - std::cerr << p.parser.usage_string(program_name) << '\n'; + std::cerr << p.value.usage_string(program_name) << '\n'; fmt::print(std::cerr, "Invalid {} value '{}' given for '{}'\n", - arg.argument.valname, - val.given, - spell.spelling); + arg.value.valname, + val.value, + spell.value); return 2; }, [&](debate::invalid_arguments, @@ -94,43 +92,43 @@ int main_fn(std::string_view program_name, const std::vector& argv) debate::e_arg_spelling spell, debate::e_argument arg, debate::e_wrong_val_num given) { - std::cerr << p.parser.usage_string(program_name) << '\n'; - if (arg.argument.nargs == 0) { + std::cerr << p.value.usage_string(program_name) << '\n'; + if (arg.value.nargs == 0) { fmt::print(std::cerr, "Argument '{}' does not expect any values, but was given one\n", - spell.spelling); - } else if (arg.argument.nargs == 1 && given.n_given == 0) { + spell.value); + } else if (arg.value.nargs == 1 && given.value == 0) { fmt::print(std::cerr, "Argument '{}' expected to be given a value, but received none\n", - spell.spelling); + spell.value); } else { fmt::print( std::cerr, "Wrong number of arguments provided for '{}': Expected {}, but only got {}\n", - spell.spelling, - arg.argument.nargs, - given.n_given); + spell.value, + arg.value.nargs, + given.value); } return 2; }, [&](debate::missing_required, debate::e_argument_parser p, debate::e_argument arg) { fmt::print(std::cerr, "{}\nMissing required argument '{}'\n", - p.parser.usage_string(program_name), - arg.argument.preferred_spelling()); + p.value.usage_string(program_name), + arg.value.preferred_spelling()); return 2; }, [&](debate::invalid_repetition, debate::e_argument_parser p, debate::e_arg_spelling sp) { fmt::print(std::cerr, "{}\nArgument '{}' cannot be provided more than once\n", - p.parser.usage_string(program_name), - sp.spelling); + p.value.usage_string(program_name), + sp.value); return 2; }, [&](debate::invalid_arguments const& err, debate::e_argument_parser p) { fmt::print(std::cerr, "{}\nError: {}\n", - p.parser.usage_string(program_name), + p.value.usage_string(program_name), err.what()); return 2; }); diff --git a/src/debate/argument_parser.test.cpp b/src/debate/argument_parser.test.cpp index 8044f779..1c68a93b 100644 --- a/src/debate/argument_parser.test.cpp +++ b/src/debate/argument_parser.test.cpp @@ -2,6 +2,7 @@ #include "./enum.hpp" +#include #include TEST_CASE("Create an argument parser") { @@ -28,20 +29,20 @@ TEST_CASE("Create an argument parser") { .valname = "", .action = debate::put_into(file), }); - parser.parse_argv({"--log-level=info"}); + REQUIRES_LEAF_NOFAIL(parser.parse_argv({"--log-level=info"})); CHECK(level == log_level::info); - parser.parse_argv({"--log-level=warning"}); + REQUIRES_LEAF_NOFAIL(parser.parse_argv({"--log-level=warning"})); CHECK(level == log_level::warning); - parser.parse_argv({"--log-level", "info"}); + REQUIRES_LEAF_NOFAIL(parser.parse_argv({"--log-level", "info"})); CHECK(level == log_level::info); - parser.parse_argv({"-lerror"}); + REQUIRES_LEAF_NOFAIL(parser.parse_argv({"-lerror"})); CHECK(level == log_level::error); CHECK_THROWS_AS(parser.parse_argv({"-lerror", "--log-level=info"}), std::runtime_error); - parser.parse_argv({"-l", "info"}); + REQUIRES_LEAF_NOFAIL(parser.parse_argv({"-l", "info"})); CHECK(level == log_level::info); - parser.parse_argv({"-lwarning", "my-file.txt"}); + REQUIRES_LEAF_NOFAIL(parser.parse_argv({"-lwarning", "my-file.txt"})); CHECK(level == log_level::warning); CHECK(file == "my-file.txt"); } diff --git a/src/debate/error.hpp b/src/debate/error.hpp index f278c150..061425d9 100644 --- a/src/debate/error.hpp +++ b/src/debate/error.hpp @@ -29,27 +29,27 @@ struct invalid_repetition : invalid_arguments { }; struct e_argument { - const debate::argument& argument; + const debate::argument& value; }; struct e_argument_parser { - const debate::argument_parser& parser; + const debate::argument_parser& value; }; struct e_invalid_arg_value { - std::string given; + std::string value; }; struct e_wrong_val_num { - int n_given; + int value; }; struct e_arg_spelling { - std::string spelling; + std::string value; }; struct e_did_you_mean { - std::string candidate; + std::string value; }; } // namespace debate From 41f12438b238352eea1b9356a33ed5d93eae01aa Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 23:17:29 -0600 Subject: [PATCH 04/62] Fix wrong generated paths when a relative path is provided for `--project` --- src/bpt/build/plan/compile_file.cpp | 5 +---- src/bpt/cli/cmd/build_common.cpp | 4 ++-- src/bpt/cli/cmd/pkg_create.cpp | 2 +- src/bpt/cli/options.cpp | 4 ++++ src/bpt/cli/options.hpp | 3 +++ src/bpt/toolchain/toolchain.cpp | 5 +++-- tests/test_basics.py | 33 +++++++++++++++++++++++++++++ tools/bpt_ci/bpt.py | 5 ++++- tools/bpt_ci/testing/fixtures.py | 6 ++++-- 9 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/bpt/build/plan/compile_file.cpp b/src/bpt/build/plan/compile_file.cpp index 7d1aa043..d9f27e22 100644 --- a/src/bpt/build/plan/compile_file.cpp +++ b/src/bpt/build/plan/compile_file.cpp @@ -18,10 +18,7 @@ compile_command_info compile_file_plan::generate_compile_command(build_env_ref e spec.enable_warnings = _rules.enable_warnings(); spec.syntax_only = _rules.syntax_only(); for (auto dirpath : _rules.include_dirs()) { - if (!dirpath.is_absolute()) { - dirpath = env.output_root / dirpath; - } - dirpath = fs::weakly_canonical(dirpath); + dirpath = bpt::resolve_path_weak(dirpath); spec.include_dirs.push_back(std::move(dirpath)); } for (const auto& use : _rules.uses()) { diff --git a/src/bpt/cli/cmd/build_common.cpp b/src/bpt/cli/cmd/build_common.cpp index 3992bc9d..b87d4ddd 100644 --- a/src/bpt/cli/cmd/build_common.cpp +++ b/src/bpt/cli/cmd/build_common.cpp @@ -50,7 +50,7 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { auto cache = open_ready_cache(opts); auto& meta_db = cache.db(); - sdist proj_sd = bpt_leaf_try { return sdist::from_directory(opts.project_dir); } + sdist proj_sd = bpt_leaf_try { return sdist::from_directory(opts.absolute_project_dir_path()); } bpt_leaf_catch(bpt::e_missing_pkg_json, bpt::e_missing_project_yaml) { crs::package_info default_meta; default_meta.id.name.str = "anon"; @@ -58,7 +58,7 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { crs::library_info default_library; default_library.name.str = "anon"; default_meta.libraries.push_back(default_library); - return sdist{std::move(default_meta), opts.project_dir}; + return sdist{std::move(default_meta), opts.absolute_project_dir_path()}; }; builder builder; diff --git a/src/bpt/cli/cmd/pkg_create.cpp b/src/bpt/cli/cmd/pkg_create.cpp index 7bfdabb0..99a00e8e 100644 --- a/src/bpt/cli/cmd/pkg_create.cpp +++ b/src/bpt/cli/cmd/pkg_create.cpp @@ -18,7 +18,7 @@ namespace bpt::cli::cmd { int pkg_create(const options& opts) { bpt::sdist_params params{ - .project_dir = opts.project_dir, + .project_dir = opts.absolute_project_dir_path(), .dest_path = {}, .force = opts.if_exists == if_exists::replace, }; diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 7b53a735..f82e66eb 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -454,3 +454,7 @@ toolchain bpt::cli::options::load_toolchain() const { return parse_toolchain_json5(bpt::read_file(tc_str)); } } + +fs::path bpt::cli::options::absolute_project_dir_path() const noexcept { + return bpt::resolve_path_weak(project_dir); +} diff --git a/src/bpt/cli/options.hpp b/src/bpt/cli/options.hpp index 3f5d1685..a100b100 100644 --- a/src/bpt/cli/options.hpp +++ b/src/bpt/cli/options.hpp @@ -112,6 +112,9 @@ struct options { // Many subcommands use a '--project' argument, stored here, using the CWD as the default path project_dir = fs::current_path(); + // Obtain the absolute path specified by 'project_dir' (resolve using the CWD) + path absolute_project_dir_path() const noexcept; + // Compile and build commands with `--no-warnings`/`--no-warn` bool disable_warnings = false; // Compile and build commands' `--jobs` parameter diff --git a/src/bpt/toolchain/toolchain.cpp b/src/bpt/toolchain/toolchain.cpp index 51c2de0b..e772a8a5 100644 --- a/src/bpt/toolchain/toolchain.cpp +++ b/src/bpt/toolchain/toolchain.cpp @@ -132,10 +132,11 @@ compile_command_info toolchain::create_compile_command(const compile_file_spec& bpt_log(trace, "Syntax check file: {}", in_file); fs::create_directories(in_file.parent_path()); - bpt::write_file(in_file, fmt::format("#include \"{}\"", spec.source_path.string())); + auto abs_path = bpt::resolve_path_weak(spec.source_path); + bpt::write_file(in_file, fmt::format("#include \"{}\"", abs_path.string())); } - bpt_log(trace, "#include-search dirs:"); + bpt_log(trace, "#include search-dirs:"); for (auto&& inc_dir : spec.include_dirs) { bpt_log(trace, " - search: {}", inc_dir.string()); auto shortest = shortest_path_from(inc_dir, cwd); diff --git a/tests/test_basics.py b/tests/test_basics.py index 68c1c68e..250bed06 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -1,11 +1,14 @@ +from pathlib import Path import time from subprocess import CalledProcessError import pytest from bpt_ci import paths +from bpt_ci.bpt import BPTWrapper from bpt_ci.testing import Project, PkgYAML from bpt_ci.testing.error import expect_error_marker from bpt_ci.testing.fixtures import ProjectOpener +from bpt_ci.testing.fs import render_into def test_build_empty(tmp_project: Project) -> None: @@ -173,3 +176,33 @@ def test_link_interdep(project_opener: ProjectOpener) -> None: print(proj.pkg_yaml) # Build is okay now proj.build() + + +def test_build_other_dir(project_opener: ProjectOpener, tmp_path: Path, bpt: BPTWrapper): + render_into( + tmp_path, { + 'build-other-dir': { + 'src': { + 'foo/': { + 'foo.hpp': + r''' + extern int get_value(); + ''', + 'foo.cpp': + r''' + #include + int get_value() { return 42; } + ''', + 'foo.test.cpp': + r''' + #include + int main() { + return get_value() != 42; + } + ''' + } + } + } + }) + proj = Project(Path('./build-other-dir/'), bpt) + proj.build(cwd=tmp_path) diff --git a/tools/bpt_ci/bpt.py b/tools/bpt_ci/bpt.py index a3e4beda..2a34ab0f 100644 --- a/tools/bpt_ci/bpt.py +++ b/tools/bpt_ci/bpt.py @@ -89,7 +89,8 @@ def build(self, with_tests: bool = True, repos: Iterable[Pathish] = (), more_args: proc.CommandLine | None = None, - timeout: float | None = None) -> None: + timeout: float | None = None, + cwd: Pathish | None = None) -> None: """ Run 'bpt build' with the given arguments. @@ -102,6 +103,7 @@ def build(self, :param repos: Repositories to use during the build. :param more_args: Additional command-line arguments. :param timeout: Timeout for the build subprocess. + :param cwd: Working directory for the bpt subprocess """ toolchain = toolchain or tc_mod.get_default_audit_toolchain() jobs = jobs or multiprocessing.cpu_count() + 2 @@ -119,6 +121,7 @@ def build(self, more_args or (), ], timeout=timeout, + cwd=cwd, ) def compile_file(self, diff --git a/tools/bpt_ci/testing/fixtures.py b/tools/bpt_ci/testing/fixtures.py index df7451d1..229ca932 100644 --- a/tools/bpt_ci/testing/fixtures.py +++ b/tools/bpt_ci/testing/fixtures.py @@ -266,7 +266,8 @@ def build(self, tweaks_dir: Optional[Path] = None, with_tests: bool = True, repos: Sequence[Pathish] = (), - log_level: Literal['info', 'debug', 'trace'] = 'trace') -> None: + log_level: Literal['info', 'debug', 'trace'] = 'trace', + cwd: Pathish | None = None) -> None: """ Execute 'bpt build' on the project """ @@ -282,7 +283,8 @@ def build(self, tweaks_dir=tweaks_dir, with_tests=with_tests, repos=repos, - more_args=[f'--log-level={log_level}']) + more_args=[f'--log-level={log_level}'], + cwd=cwd) def compile_file(self, *paths: Pathish, toolchain: Optional[Pathish] = None) -> None: with tc_mod.fixup_toolchain(toolchain or tc_mod.get_default_test_toolchain()) as tc: From 65c73887391b07339b1f911f10022456e6fe153c Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 23:18:29 -0600 Subject: [PATCH 05/62] Handle generic errors that provide a doc ref, message, and (optional) marker --- src/bpt/cli/error_handler.cpp | 13 +++++++++++++ src/bpt/error/marker.hpp | 5 +++++ src/bpt/toolchain/toolchain.cpp | 4 +++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/bpt/cli/error_handler.cpp b/src/bpt/cli/error_handler.cpp index 9e818abe..7887ff7a 100644 --- a/src/bpt/cli/error_handler.cpp +++ b/src/bpt/cli/error_handler.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -234,6 +235,18 @@ auto handlers = std::tuple( // bpt_log(trace, "Additional error information: {}", info); return ex.value; }, + [](bpt::e_human_message message, + bpt::e_doc_ref docref, + boost::leaf::verbose_diagnostic_info const& diag, + bpt::e_error_marker const* marker) { + bpt_log(error, "Error: .bold.red[{}]"_styled, message.value); + bpt_log(error, "Refer: .bold.yellow[https://dds`.pizza/docs/{}]"_styled, docref.value); + bpt_log(debug, "Additional diagnostic objects:\n.blue[{}]"_styled, diag); + if (marker) { + bpt::write_error_marker(marker->value); + } + return 1; + }, [](catch_ exc, boost::leaf::verbose_diagnostic_info const& diag) { bpt_log(critical, "An unhandled SQLite error arose. .bold.red[THIS IS A BPT BUG!] Info: {}"_styled, diff --git a/src/bpt/error/marker.hpp b/src/bpt/error/marker.hpp index 2acab27d..c54f5213 100644 --- a/src/bpt/error/marker.hpp +++ b/src/bpt/error/marker.hpp @@ -1,9 +1,14 @@ #pragma once +#include #include namespace bpt { void write_error_marker(std::string_view) noexcept; +struct e_error_marker { + std::string value; +}; + } // namespace bpt \ No newline at end of file diff --git a/src/bpt/toolchain/toolchain.cpp b/src/bpt/toolchain/toolchain.cpp index e772a8a5..0aad9281 100644 --- a/src/bpt/toolchain/toolchain.cpp +++ b/src/bpt/toolchain/toolchain.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -352,5 +353,6 @@ bpt::toolchain bpt::toolchain::get_default() { } } BOOST_LEAF_THROW_EXCEPTION(e_human_message{neo::ufmt("No default toolchain")}, - BPT_ERR_REF("no-default-toolchain")); + BPT_ERR_REF("no-default-toolchain"), + e_error_marker{"no-default-toolchain"}); } From f5e3700d6e357370b5f6fa230d8a28bdd7c90a50 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 23:24:18 -0600 Subject: [PATCH 06/62] A very simple 'new' subcommand --- src/bpt.main.cpp | 5 +- src/bpt/cli/cmd/new.cpp | 150 ++++++++++++++++++++++++++++++++++ src/bpt/cli/dispatch_main.cpp | 3 + src/bpt/cli/options.cpp | 22 +++++ src/bpt/cli/options.hpp | 8 ++ src/fansi/style.hpp | 2 +- 6 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 src/bpt/cli/cmd/new.cpp diff --git a/src/bpt.main.cpp b/src/bpt.main.cpp index c4bbe4e5..b9cc4648 100644 --- a/src/bpt.main.cpp +++ b/src/bpt.main.cpp @@ -39,7 +39,6 @@ int main_fn(std::string_view program_name, const std::vector& argv) load_locale(); std::setlocale(LC_CTYPE, ".utf8"); - bpt::install_signal_handlers(); bpt::enable_ansi_console(); bpt::cli::options opts; @@ -136,6 +135,10 @@ int main_fn(std::string_view program_name, const std::vector& argv) // Non-null result from argument parsing, return that value immediately. return *result; } + if (opts.subcommand != bpt::cli::subcommand::new_) { + // We want ^C to behave as-normal for 'new' + bpt::install_signal_handlers(); + } bpt::log::current_log_level = opts.log_level; return bpt::cli::dispatch_main(opts); } diff --git a/src/bpt/cli/cmd/new.cpp b/src/bpt/cli/cmd/new.cpp new file mode 100644 index 00000000..a7b25ef9 --- /dev/null +++ b/src/bpt/cli/cmd/new.cpp @@ -0,0 +1,150 @@ +#include "../options.hpp" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +using namespace bpt; +using namespace fansi::literals; + +namespace bpt::cli::cmd { + +namespace { + +std::string get_argument(std::string_view prompt, + std::optional const& opt, + std::string_view default_) { + if (opt.has_value()) { + return opt.value(); + } + if (default_.empty()) { + fmt::print(".magenta[{}]: "_styled, prompt, default_); + } else { + fmt::print(".magenta[{}] [.blue[{}]]: "_styled, prompt, default_); + } + std::string ret; + std::getline(std::cin, ret); + if (!std::cin.good()) { + throw bpt::user_cancelled{}; + } + if (ret.empty()) { + return std::string(default_); + } + return ret; +} + +std::string to_ident(std::string_view given) { + std::string ret; + std::ranges::replace_copy_if(given, std::back_inserter(ret), NEO_TL(!std::isalnum(_1)), '_'); + if (!ret.empty() && std::isdigit(ret.front())) { + ret.insert(ret.begin(), '_'); + } + return ret; +} + +} // namespace + +int new_cmd(const options& opts) { + auto given_name = opts.new_.name; + std::string name; + while (name.empty()) { + bpt_leaf_try { + name = bpt::name::from_string(get_argument("New project name", given_name, ""))->str; + } + bpt_leaf_catch(bpt::e_name_str given, bpt::invalid_name_reason why) { + given_name.reset(); + fmt::print(std::cerr, + "Invalid name string \".bold.red[{}]\": .bold.yellow[{}]\n"_styled, + given.value, + bpt::invalid_name_reason_str(why)); + }; + } + + std::string dest; + while (dest.empty()) { + auto default_dir = bpt::resolve_path_weak(fs::absolute(name)); + dest = get_argument("Project directory", opts.new_.directory, default_dir.string()); + if (dest.empty()) { + continue; + } + dest = bpt::resolve_path_weak(fs::absolute(dest)).string(); + if (fs::exists(dest)) { + if (!fs::is_directory(dest)) { + fmt::print(std::cerr, + "Path [.bold.red[{}]] names an existing non-directory file\n"_styled, + dest); + dest.clear(); + continue; + } + if (fs::directory_iterator{dest} != fs::directory_iterator{}) { + fmt::print(std::cerr, + "Path [.bold.red[{}]] is an existing non-empty directory\n"_styled, + dest); + dest.clear(); + continue; + } + } + } + + bool split_dir = false; + while (true) { + auto got = get_argument( + "Split headers and sources into [include/] and [src/] directories? [y/N]", + std::nullopt, + ""); + if (got == neo::oper::any_of("n", "N", "no", "")) { + split_dir = false; + break; + } else if (got == neo::oper::any_of("y", "Y", "yes")) { + split_dir = true; + break; + } else { + fmt::print(std::cerr, "Enter one of '.bold.cyan[y]' or '.bold.cyan[n]'"_styled); + } + } + + fs::path project_dir = dest; + fs::create_directories(project_dir); + bpt::write_file(project_dir / "pkg.yaml", + fmt::format("# Project '{0}' created by 'bpt new'\n" + "name: {0}\n" + "version: 0.1.0\n" + "lib:\n" + " name: {0}\n", + name)); + + fs::path header_dir = split_dir ? (project_dir / "include") : (project_dir / "src"); + fs::path src_dir = project_dir / "src"; + fs::create_directories(header_dir / name); + fs::create_directories(src_dir / name); + bpt::write_file(src_dir / name / fmt::format("{}.cpp", name), + fmt::format("#include <{0}/{0}.hpp>\n\n" + "int {1}::the_answer() noexcept {{\n" + " return 42;\n" + "}}\n", + name, + to_ident(name))); + + bpt::write_file(header_dir / name / fmt::format("{}.hpp", name), + fmt::format("#pragma once\n\n" + "namespace {0} {{\n\n" + "// Calculate the answer\n" + "int the_answer() noexcept;\n\n" + "}}\n", + to_ident(name))); + + fmt::print("New project files written to [.bold.cyan[{}]]\n"_styled, dest); + return 0; +} + +} // namespace bpt::cli::cmd diff --git a/src/bpt/cli/dispatch_main.cpp b/src/bpt/cli/dispatch_main.cpp index 8687b60c..b784cc5a 100644 --- a/src/bpt/cli/dispatch_main.cpp +++ b/src/bpt/cli/dispatch_main.cpp @@ -22,6 +22,7 @@ command pkg_search; command pkg_prefetch; command pkg_solve; command repo_cmd; +command new_cmd; } // namespace cmd @@ -29,6 +30,8 @@ int dispatch_main(const options& opts) noexcept { return bpt::handle_cli_errors([&] { BPT_E_SCOPE(opts.subcommand); switch (opts.subcommand) { + case subcommand::new_: + return cmd::new_cmd(opts); case subcommand::build: return cmd::build(opts); case subcommand::pkg: { diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index f82e66eb..3b7378ff 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -183,6 +183,10 @@ struct setup { .name = "install-yourself", .help = "Have this bpt executable install itself onto your PATH", })); + setup_new_cmd(group.add_parser({ + .name = "new", + .help = "Generate a new bpt project", + })); } void add_repo_args(argument_parser& cmd) { @@ -431,6 +435,24 @@ struct setup { .action = store_true(opts.install_yourself.symlink), }); } + + void setup_new_cmd(argument_parser& parser) { + parser.add_argument({ + .help = "Name for the new project", + .valname = "", + .action = put_into(opts.new_.name), + }); + // parser.add_argument({ + // .long_spellings = {"name"}, + // .action = store_value(opts.new_.name), + // }); + parser.add_argument({ + .long_spellings = {"dir"}, + .help = "Directory in which the project will be generated", + .valname = "", + .action = put_into(opts.new_.directory), + }); + } }; } // namespace diff --git a/src/bpt/cli/options.hpp b/src/bpt/cli/options.hpp index a100b100..0a83f4d9 100644 --- a/src/bpt/cli/options.hpp +++ b/src/bpt/cli/options.hpp @@ -26,6 +26,7 @@ enum class subcommand { pkg, repo, install_yourself, + new_, }; /** @@ -236,6 +237,13 @@ struct options { bool symlink = false; } install_yourself; + struct { + /// The directory in which to create the new project + opt_string directory; + /// The name of the new project + opt_string name; + } new_; + /** * @brief Attach arguments and subcommands to the given argument parser, binding those arguments * to the values in this object. diff --git a/src/fansi/style.hpp b/src/fansi/style.hpp index a4476a68..84a1f91e 100644 --- a/src/fansi/style.hpp +++ b/src/fansi/style.hpp @@ -11,7 +11,7 @@ enum class std_color { green = 2, yellow = 3, blue = 4, - magent = 5, + magenta = 5, cyan = 6, white = 7, normal = 9, From e914950aa9ff60226e1c7e4dfa22feffc5b50d49 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 3 Apr 2022 23:48:27 -0600 Subject: [PATCH 07/62] Properly validate and catch crs.json errors --- src/bpt/cli/error_handler.cpp | 30 ++++++++++++++++++++++------- src/bpt/crs/info/library.cpp | 8 +++++--- tests/test_pkg.py | 36 +++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 10 deletions(-) diff --git a/src/bpt/cli/error_handler.cpp b/src/bpt/cli/error_handler.cpp index 7887ff7a..05114aaa 100644 --- a/src/bpt/cli/error_handler.cpp +++ b/src/bpt/cli/error_handler.cpp @@ -2,6 +2,7 @@ #include "./options.hpp" #include +#include #include #include #include @@ -83,13 +84,28 @@ auto handlers = std::tuple( // } return 1; }, - [](const semester::walk_error& exc, - e_sdist_from_directory, - e_parse_project_manifest_path pkg_yaml) { - bpt_log(error, - "Error loading project info from [.bold.yellow[{}]]: .bold.red[{}]"_styled, - pkg_yaml.value.string(), - exc.what()); + [](const semester::walk_error& exc, + e_sdist_from_directory dir, + e_parse_project_manifest_path* pkg_yaml, + crs::e_pkg_json_path* pkg_json) { + if (pkg_json) { + bpt_log(error, + "Error loading package info from [.bold.yellow[{}]]: .bold.red[{}]"_styled, + pkg_json->value.string(), + exc.what()); + write_error_marker("invalid-pkg-json"); + } else if (pkg_yaml) { + bpt_log(error, + "Error loading project info from [.bold.yellow[{}]]: .bold.red[{}]"_styled, + pkg_yaml->value.string(), + exc.what()); + write_error_marker("invalid-pkg-yaml"); + } else { + bpt_log(error, + "Error parsing data in directory [.bold.yellow[{}]]: .bold.red[{}]"_styled, + dir.value.string(), + exc.what()); + } return 1; }, [](const neo::url_validation_error& exc, diff --git a/src/bpt/crs/info/library.cpp b/src/bpt/crs/info/library.cpp index f501f1a8..3b88a19b 100644 --- a/src/bpt/crs/info/library.cpp +++ b/src/bpt/crs/info/library.cpp @@ -41,13 +41,15 @@ library_info library_info::from_data(const json5::data& data) { required_key{"using", "A 'using' array is required", require_array{"A library's 'using' must be an array of usage objects"}, - for_each{ - put_into{std::back_inserter(ret.intra_using), name_from_string{}}}}, + for_each{require_str{"Each 'using' element must be a string"}, + put_into{std::back_inserter(ret.intra_using), + name_from_string{}}}}, required_key{"test-using", "A 'test-using' array is required", require_array{ "A library's 'test-using' must be an array of usage objects"}, - for_each{put_into{std::back_inserter(ret.intra_test_using), + for_each{require_str{"Each 'using' element must be a string"}, + put_into{std::back_inserter(ret.intra_test_using), name_from_string{}}}}, required_key{"dependencies", "A 'dependencies' array is required", diff --git a/tests/test_pkg.py b/tests/test_pkg.py index 93793c65..07d3ed79 100644 --- a/tests/test_pkg.py +++ b/tests/test_pkg.py @@ -98,3 +98,39 @@ def test_pkg_spdx(tmp_project: Project) -> None: assert 'meta' in pkg_json assert 'license' in pkg_json['meta'] assert pkg_json['meta']['license'] == 'MIT' + + +def test_pkg_create_almost_valid(tmp_project: Project) -> None: + tmp_project.write( + 'pkg.json', + json.dumps({ + "name": + "catch2", + "version": + "2.13.6", + "pkg-version": + 1, + "libraries": [{ + "name": "catch2", + "path": ".", + "using": [], + "test-using": [], + "dependencies": [], + "test-dependencies": [] + }, { + "name": "main", + "path": "libs/main", + "test-dependencies": [], + "dependencies": [], + "test-using": [], + "using": [{ + "lib": "catch2" + }] + }], + "schema-version": + 1 + })) + with error.expect_error_marker('invalid-pkg-json'): + tmp_project.build() + with error.expect_error_marker('invalid-pkg-json'): + tmp_project.pkg_create() From 24bd0b8ef0692d2c20e35ae120937b2e19dad735 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 10 Apr 2022 16:10:24 -0600 Subject: [PATCH 08/62] Specify some options with environment variables --- src/bpt/cli/cmd/cache_util.cpp | 6 +++-- src/bpt/cli/options.cpp | 47 ++++++++++++++++++++++++++++++++++ src/bpt/cli/options.hpp | 12 ++++++--- src/bpt/util/env.cpp | 4 +++ src/bpt/util/env.hpp | 2 ++ 5 files changed, 66 insertions(+), 5 deletions(-) diff --git a/src/bpt/cli/cmd/cache_util.cpp b/src/bpt/cli/cmd/cache_util.cpp index c72eef3f..771c7c84 100644 --- a/src/bpt/cli/cmd/cache_util.cpp +++ b/src/bpt/cli/cmd/cache_util.cpp @@ -22,6 +22,9 @@ using namespace fansi::literals; static void use_repo(bpt::crs::cache_db& meta_db, const cli::options& opts, std::string_view url_or_path) { + if (url_or_path == ":default") { + url_or_path = "https://repo-3.bpt.pizza/"; + } // Convert what may be just a domain name or partial URL into a proper URL: auto url = bpt::guess_url_from_string(url_or_path); // Called by error handler to decide whether to rethrow: @@ -138,8 +141,7 @@ use_repo(bpt::crs::cache_db& meta_db, const cli::options& opts, std::string_view } crs::cache cli::open_ready_cache(const cli::options& opts) { - auto cache - = bpt::crs::cache::open(opts.crs_cache_dir.value_or(bpt::crs::cache::default_path())); + auto cache = bpt::crs::cache::open(opts.crs_cache_dir); auto& meta_db = cache.db(); for (auto& r : opts.use_repos) { use_repo(meta_db, opts, r); diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 3b7378ff..6cb3dcd5 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -1,11 +1,13 @@ #include "./options.hpp" +#include #include #include #include #include #include #include +#include #include #include @@ -480,3 +482,48 @@ toolchain bpt::cli::options::load_toolchain() const { fs::path bpt::cli::options::absolute_project_dir_path() const noexcept { return bpt::resolve_path_weak(project_dir); } + +bool cli::options::default_from_env(std::string key, bool def) noexcept { + auto env = bpt::getenv(key); + if (env.has_value()) { + return is_truthy_string(*env); + } + return def; +} + +std::string cli::options::default_from_env(std::string key, std::string def) noexcept { + return bpt::getenv(key).value_or(def); +} + +int cli::options::default_from_env(std::string key, int def) noexcept { + auto env = bpt::getenv(key); + if (!env.has_value()) { + return def; + } + int r = 0; + const auto dat = env->data(); + const auto dat_end = dat + env->size(); + auto res = std::from_chars(dat, dat_end, r); + if (res.ptr != dat_end) { + return def; + } + return r; +} + +cli::options::options() noexcept { + crs_cache_dir = bpt::getenv("BPT_CRS_CACHE_DIR", [] { return crs::cache::default_path(); }); + + auto ll = getenv("BPT_LOG_LEVEL"); + if (ll.has_value()) { + auto llo = magic_enum::enum_cast(*ll); + if (llo.has_value()) { + log_level = *llo; + } + } + + toolchain = getenv("BPT_TOOLCHAIN"); + auto out = getenv("BPT_OUTPUT_PATH"); + if (out.has_value()) { + out_path = *out; + } +} diff --git a/src/bpt/cli/options.hpp b/src/bpt/cli/options.hpp index 0a83f4d9..eb1f2406 100644 --- a/src/bpt/cli/options.hpp +++ b/src/bpt/cli/options.hpp @@ -93,8 +93,10 @@ struct options { using string = std::string; using opt_string = std::optional; + options() noexcept; + // The `--crs-cache-dir` argument - opt_path crs_cache_dir; + path crs_cache_dir; // The `--log-level` argument log::level log_level = log::level::info; // Any `--dry-run` argument @@ -105,7 +107,7 @@ struct options { // All `--use-repo` arguments std::vector use_repos; // Toggle on/off the default repository - bool use_default_repo = true; + bool use_default_repo = !default_from_env("BPT_NO_DEFAULT_REPO", false); // The top-most selected subcommand enum subcommand subcommand; @@ -119,7 +121,7 @@ struct options { // Compile and build commands with `--no-warnings`/`--no-warn` bool disable_warnings = false; // Compile and build commands' `--jobs` parameter - int jobs = 0; + int jobs = default_from_env("BPT_JOBS", 0); // Compile and build commands' `--toolchain` option: opt_string toolchain; opt_path out_path; @@ -249,6 +251,10 @@ struct options { * to the values in this object. */ void setup_parser(debate::argument_parser& parser) noexcept; + + static bool default_from_env(string env_var, bool default_value) noexcept; + static string default_from_env(string env_var, string default_value) noexcept; + static int default_from_env(string env_var, int default_value) noexcept; }; } // namespace cli diff --git a/src/bpt/util/env.cpp b/src/bpt/util/env.cpp index 9f523f5d..07e7c4b6 100644 --- a/src/bpt/util/env.cpp +++ b/src/bpt/util/env.cpp @@ -14,5 +14,9 @@ std::optional bpt::getenv(const std::string& varname) noexcept { bool bpt::getenv_bool(const std::string& varname) noexcept { auto s = getenv(varname); + return s.has_value() && is_truthy_string(*s); +} + +bool bpt::is_truthy_string(std::string_view s) noexcept { return s == neo::oper::any_of("1", "true", "on", "TRUE", "ON", "YES", "yes"); } diff --git a/src/bpt/util/env.hpp b/src/bpt/util/env.hpp index 9c2e28dd..659d70c1 100644 --- a/src/bpt/util/env.hpp +++ b/src/bpt/util/env.hpp @@ -11,6 +11,8 @@ std::optional getenv(const std::string& env) noexcept; bool getenv_bool(const std::string& env) noexcept; +bool is_truthy_string(std::string_view s) noexcept; + template std::string getenv(const std::string& name, Func&& fn) noexcept(noexcept(fn())) { auto val = getenv(name); From d5688e5ec13bce8480af431be7012ee7ae088989 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 10 Apr 2022 21:45:49 -0600 Subject: [PATCH 09/62] pkg.yaml -> bpt.yaml --- pkg.yaml => bpt.yaml | 0 data/projects/simple/{pkg.yaml => bpt.yaml} | 0 docs/dev/testing.rst | 2 +- docs/err/unknown-usage.rst | 2 +- docs/tut/hello-test.rst | 4 ++-- docs/tut/hello-world.rst | 6 ++--- src/bpt/cli/cmd/new.cpp | 2 +- src/bpt/cli/error_handler.cpp | 18 +++++++-------- src/bpt/project/dependency.walk.cpp | 4 ++-- src/bpt/project/error.hpp | 2 +- src/bpt/project/library.walk.cpp | 2 +- src/bpt/project/project.cpp | 14 ++++++------ src/bpt/project/project.walk.cpp | 2 +- src/bpt/sdist/dist.cpp | 10 ++++----- .../proj-exec/{pkg.yaml => bpt.yaml} | 0 tests/projects/simple/{pkg.yaml => bpt.yaml} | 0 tests/projects/tweaks/{pkg.yaml => bpt.yaml} | 0 tests/self-uses-rejected/test_self_uses.py | 6 ++--- tests/test_basics.py | 22 +++++++++---------- tests/test_pkg.py | 10 ++++----- tests/test_pkg_solve.py | 4 ++-- tests/test_repo/test_repo.py | 4 ++-- .../basic_dependent/{pkg.yaml => bpt.yaml} | 0 .../{pkg.yaml => bpt.yaml} | 0 .../{pkg.yaml => bpt.yaml} | 0 .../{pkg.yaml => bpt.yaml} | 0 tests/test_uses/test_uses_test.py | 4 ++-- .../{pkg.yaml => bpt.yaml} | 0 .../the_test_lib/{pkg.yaml => bpt.yaml} | 0 .../unbuildable/{pkg.yaml => bpt.yaml} | 0 .../with_bad_test_dep/{pkg.yaml => bpt.yaml} | 0 .../{pkg.yaml => bpt.yaml} | 0 .../use-spdlog/project/{pkg.yaml => bpt.yaml} | 0 tests/use-spdlog/use_spdlog_test.py | 2 +- tools/bpt_ci/tasks.py | 4 ++-- tools/bpt_ci/testing/fixtures.py | 14 ++++++------ 36 files changed, 69 insertions(+), 69 deletions(-) rename pkg.yaml => bpt.yaml (100%) rename data/projects/simple/{pkg.yaml => bpt.yaml} (100%) rename tests/colliding_libs_objects/proj-exec/{pkg.yaml => bpt.yaml} (100%) rename tests/projects/simple/{pkg.yaml => bpt.yaml} (100%) rename tests/projects/tweaks/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/dependents/basic_dependent/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/dependents/basic_test_dependent/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/dependents/multi_lib_dependent/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/dependents/test_depends_but_regular_uses/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/the_test_dependency/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/the_test_lib/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/unbuildable/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/with_bad_test_dep/{pkg.yaml => bpt.yaml} (100%) rename tests/test_uses/with_transitive_bad_test_dep/{pkg.yaml => bpt.yaml} (100%) rename tests/use-spdlog/project/{pkg.yaml => bpt.yaml} (100%) diff --git a/pkg.yaml b/bpt.yaml similarity index 100% rename from pkg.yaml rename to bpt.yaml diff --git a/data/projects/simple/pkg.yaml b/data/projects/simple/bpt.yaml similarity index 100% rename from data/projects/simple/pkg.yaml rename to data/projects/simple/bpt.yaml diff --git a/docs/dev/testing.rst b/docs/dev/testing.rst index fc628a1e..c0b1d664 100644 --- a/docs/dev/testing.rst +++ b/docs/dev/testing.rst @@ -67,7 +67,7 @@ To write a test that checks for a given error-handling path, use the def test_sdist_invalid_project(tmp_project: Project) -> None: # Trying to create a package archive from a project without a - # pkg.yaml is invalid. Check that it creates the correct + # bpt.yaml is invalid. Check that it creates the correct # error-message string with error.expect_error_marker('no-package-yaml'): tmp_project.pkg_create() diff --git a/docs/err/unknown-usage.rst b/docs/err/unknown-usage.rst index f06e1b2c..c49739ac 100644 --- a/docs/err/unknown-usage.rst +++ b/docs/err/unknown-usage.rst @@ -2,7 +2,7 @@ Error: Unknown Usage/Linking Requirements ######################################### A library can declare that it *uses* another library by using the -``using`` keyword in its ``pkg.yaml`` or ``pkg.json`` file. +``using`` keyword in its ``bpt.yaml`` or ``pkg.json`` file. These requirements are specified by using the ``name`` that identifies the library. If the ``using`` is not within a dependency declaration, then the diff --git a/docs/tut/hello-test.rst b/docs/tut/hello-test.rst index e39cef92..19997fad 100644 --- a/docs/tut/hello-test.rst +++ b/docs/tut/hello-test.rst @@ -57,13 +57,13 @@ than being a strong dependency of the library itself. A "for test" library dependency will only be available within the ``.test.*`` source files, and downstream library consumers will not see the dependency. -To declare dependencies, we return to the ``pkg.yaml`` file. We'll declare a +To declare dependencies, we return to the ``bpy.yaml`` file. We'll declare a dependency on the `Catch2`_ C and C++ unit testing framework: .. _Catch2: https://github.com/catchorg/Catch2 .. code-block:: yaml - :caption: ``/pkg.yaml`` + :caption: ``/bpy.yaml`` :emphasize-lines: 3,4 name: hello-bpt diff --git a/docs/tut/hello-world.rst b/docs/tut/hello-world.rst index 4f0cfeb2..a80aea0a 100644 --- a/docs/tut/hello-world.rst +++ b/docs/tut/hello-world.rst @@ -224,11 +224,11 @@ Creating a package manifest file. |bpt| will work happily with packages that do not declare themselves, as long as the filesystem structure is sufficient. However: To use features covered in -later tutorials, we'll need a simple ``pkg.yaml`` file to declare information +later tutorials, we'll need a simple ``bpt.yaml`` file to declare information about are package. This file should be placed directly in the package root: .. code-block:: yaml - :caption: ``/pkg.yaml`` + :caption: ``/bpt.yaml`` name: hello-bpt version: 0.1.0 @@ -236,7 +236,7 @@ about are package. This file should be placed directly in the package root: Rebuilding the project will show no difference at the moment. .. note:: - You must use the ``.yaml`` extension for this file. A ``pkg.yml`` will be + You must use the ``.yaml`` extension for this file. A ``bpt.yml`` will be ignored. .. seealso:: diff --git a/src/bpt/cli/cmd/new.cpp b/src/bpt/cli/cmd/new.cpp index a7b25ef9..94d7e94c 100644 --- a/src/bpt/cli/cmd/new.cpp +++ b/src/bpt/cli/cmd/new.cpp @@ -115,7 +115,7 @@ int new_cmd(const options& opts) { fs::path project_dir = dest; fs::create_directories(project_dir); - bpt::write_file(project_dir / "pkg.yaml", + bpt::write_file(project_dir / "bpt.yaml", fmt::format("# Project '{0}' created by 'bpt new'\n" "name: {0}\n" "version: 0.1.0\n" diff --git a/src/bpt/cli/error_handler.cpp b/src/bpt/cli/error_handler.cpp index 05114aaa..1de4beac 100644 --- a/src/bpt/cli/error_handler.cpp +++ b/src/bpt/cli/error_handler.cpp @@ -74,10 +74,10 @@ auto handlers = std::tuple( // write_error_marker("package-yaml-parse-error"); return 1; }, - [](e_sdist_from_directory, e_parse_project_manifest_path pkg_yaml, e_bad_pkg_yaml_key badkey) { + [](e_sdist_from_directory, e_parse_project_manifest_path bpt_yaml, e_bad_bpt_yaml_key badkey) { bpt_log(error, "Error loading project info from [.bold.yellow[{}]]"_styled, - pkg_yaml.value.string()); + bpt_yaml.value.string()); bpt_log(error, "Unknown project property '.bold.red[{}]'"_styled, badkey.given); if (badkey.nearest.has_value()) { bpt_log(error, " (Did you mean '.bold.green[{}]'?)"_styled, *badkey.nearest); @@ -86,7 +86,7 @@ auto handlers = std::tuple( // }, [](const semester::walk_error& exc, e_sdist_from_directory dir, - e_parse_project_manifest_path* pkg_yaml, + e_parse_project_manifest_path* bpt_yaml, crs::e_pkg_json_path* pkg_json) { if (pkg_json) { bpt_log(error, @@ -94,10 +94,10 @@ auto handlers = std::tuple( // pkg_json->value.string(), exc.what()); write_error_marker("invalid-pkg-json"); - } else if (pkg_yaml) { + } else if (bpt_yaml) { bpt_log(error, "Error loading project info from [.bold.yellow[{}]]: .bold.red[{}]"_styled, - pkg_yaml->value.string(), + bpt_yaml->value.string(), exc.what()); write_error_marker("invalid-pkg-yaml"); } else { @@ -110,27 +110,27 @@ auto handlers = std::tuple( // }, [](const neo::url_validation_error& exc, e_sdist_from_directory, - e_parse_project_manifest_path pkg_yaml, + e_parse_project_manifest_path bpt_yaml, e_url_string str) { bpt_log( error, "Error while parsing URL string '.bold.yellow[{}]' in [.bold.yellow[{}]]: .bold.red[{}]"_styled, str.value, - pkg_yaml.value.string(), + bpt_yaml.value.string(), exc.what()); return 1; }, [](bpt::e_bad_spdx_expression err, bpt::e_spdx_license_str spdx_str, e_sdist_from_directory, - e_parse_project_manifest_path pkg_yaml) { + e_parse_project_manifest_path bpt_yaml) { bpt_log(error, "Invalid SPDX license expression '.bold.yellow[{}]': .bold.red[{}]"_styled, spdx_str.value, err.value); bpt_log(error, " (While reading project manifest from [.bold.yellow[{}]]"_styled, - pkg_yaml.value.string()); + bpt_yaml.value.string()); write_error_marker("invalid-spdx"); return 1; }, diff --git a/src/bpt/project/dependency.walk.cpp b/src/bpt/project/dependency.walk.cpp index e6b1a48a..5fe75045 100644 --- a/src/bpt/project/dependency.walk.cpp +++ b/src/bpt/project/dependency.walk.cpp @@ -29,7 +29,7 @@ static auto parse_version_range = [](const json5::data& range) { require_str{"'high' version must be a string"}, put_into{high, version_from_string{}}}, if_key{"_comment", just_accept}, - dym.rejecter(), + dym.rejecter(), }); if (high <= low) { throw(semester::walk_error{"'high' version must be strictly greater than 'low' version"}); @@ -80,7 +80,7 @@ project_dependency project_dependency::from_json_data(const json5::data& data) { return walk.pass; }, put_into(std::back_inserter(explicit_uses), name_from_string{})}}, - dym.rejecter(), + dym.rejecter(), }); for (auto& ver : ver_ranges) { diff --git a/src/bpt/project/error.hpp b/src/bpt/project/error.hpp index 46fcacdb..cc2ce21d 100644 --- a/src/bpt/project/error.hpp +++ b/src/bpt/project/error.hpp @@ -19,7 +19,7 @@ struct e_open_project { std::filesystem::path value; }; -struct e_bad_pkg_yaml_key : e_nonesuch { +struct e_bad_bpt_yaml_key : e_nonesuch { using e_nonesuch::e_nonesuch; }; diff --git a/src/bpt/project/library.walk.cpp b/src/bpt/project/library.walk.cpp index 9acfd94b..2a14f9c3 100644 --- a/src/bpt/project/library.walk.cpp +++ b/src/bpt/project/library.walk.cpp @@ -49,7 +49,7 @@ project_library project_library::from_json_data(const json5::data& data) { require_array{"Library 'test-dependencies' must be an array of dependencies"}, for_each{put_into(std::back_inserter(ret.test_dependencies), project_dependency::from_json_data)}}, - dym.rejecter(), + dym.rejecter(), }); return ret; diff --git a/src/bpt/project/project.cpp b/src/bpt/project/project.cpp index e71a9272..d518dfce 100644 --- a/src/bpt/project/project.cpp +++ b/src/bpt/project/project.cpp @@ -23,18 +23,18 @@ using namespace bpt; project project::open_directory(path_ref path_) { BPT_E_SCOPE(e_open_project{path_}); auto path = resolve_path_strong(path_).value(); - auto pkg_yaml = path / "pkg.yaml"; - if (!bpt::file_exists(pkg_yaml)) { - if (bpt::file_exists(path / "pkg.yml")) { + auto bpt_yaml = path / "bpt.yaml"; + if (!bpt::file_exists(bpt_yaml)) { + if (bpt::file_exists(path / "bpt.yml")) { bpt_log(warn, - "There's a [pkg.yml] file in the project directory, but bpt expects a '.yaml' " + "There's a [bpt.yml] file in the project directory, but bpt expects a '.yaml' " "file extension. The file [{}] will be ignored.", - (path / "pkg.yml").string()); + (path / "bpt.yml").string()); } return project{path, std::nullopt}; } - BPT_E_SCOPE(e_parse_project_manifest_path{pkg_yaml}); - auto yml = bpt::parse_yaml_file(pkg_yaml); + BPT_E_SCOPE(e_parse_project_manifest_path{bpt_yaml}); + auto yml = bpt::parse_yaml_file(bpt_yaml); auto data = bpt::yaml_as_json5_data(yml); auto man = project_manifest::from_json_data(data, path); return project{path, man}; diff --git a/src/bpt/project/project.walk.cpp b/src/bpt/project/project.walk.cpp index 6dcf51bf..289248bd 100644 --- a/src/bpt/project/project.walk.cpp +++ b/src/bpt/project/project.walk.cpp @@ -146,7 +146,7 @@ project_manifest::from_json_data(const json5::data& dat require_array{"Project 'authors' must be an array of strings"}, for_each{require_str{"Each element of project 'authors' must be a string"}, put_into(std::back_inserter(authors))}}, - dym.rejecter(), + dym.rejecter(), }); if (dym.seen_keys.contains("authors")) { diff --git a/src/bpt/sdist/dist.cpp b/src/bpt/sdist/dist.cpp index 08bb07b8..39a33f1d 100644 --- a/src/bpt/sdist/dist.cpp +++ b/src/bpt/sdist/dist.cpp @@ -115,17 +115,17 @@ sdist sdist::from_directory(path_ref where) { crs::package_info meta; auto pkg_json = where / "pkg.json"; - auto pkg_yaml = where / "pkg.yaml"; + auto bpt_yaml = where / "bpt.yaml"; const bool have_pkg_json = bpt::file_exists(pkg_json); - const bool have_pkg_yaml = bpt::file_exists(pkg_yaml); + const bool have_bpt_yaml = bpt::file_exists(bpt_yaml); if (have_pkg_json) { - if (have_pkg_yaml) { + if (have_bpt_yaml) { bpt_log( warn, "Directory has both [.cyan[{}]] and [.cyan[{}]] (The .bold.cyan[pkg`.json] file will be preferred)"_styled, pkg_json.string(), - pkg_yaml.string()); + bpt_yaml.string()); } BPT_E_SCOPE(crs::e_pkg_json_path{pkg_json}); auto data = bpt::parse_json5_file(pkg_json); @@ -137,7 +137,7 @@ sdist sdist::from_directory(path_ref where) { make_user_error( "No pkg.json nor project manifest in the project directory"), e_missing_pkg_json{pkg_json}, - e_missing_project_yaml{where / "pkg.yaml"}, + e_missing_project_yaml{where / "bpt.yaml"}, BPT_ERR_REF("invalid-pkg-filesystem")); } meta = proj.manifest->as_crs_package_meta(); diff --git a/tests/colliding_libs_objects/proj-exec/pkg.yaml b/tests/colliding_libs_objects/proj-exec/bpt.yaml similarity index 100% rename from tests/colliding_libs_objects/proj-exec/pkg.yaml rename to tests/colliding_libs_objects/proj-exec/bpt.yaml diff --git a/tests/projects/simple/pkg.yaml b/tests/projects/simple/bpt.yaml similarity index 100% rename from tests/projects/simple/pkg.yaml rename to tests/projects/simple/bpt.yaml diff --git a/tests/projects/tweaks/pkg.yaml b/tests/projects/tweaks/bpt.yaml similarity index 100% rename from tests/projects/tweaks/pkg.yaml rename to tests/projects/tweaks/bpt.yaml diff --git a/tests/self-uses-rejected/test_self_uses.py b/tests/self-uses-rejected/test_self_uses.py index b87e58ef..ca8a81af 100644 --- a/tests/self-uses-rejected/test_self_uses.py +++ b/tests/self-uses-rejected/test_self_uses.py @@ -3,7 +3,7 @@ def test_self_referential_uses_fails(tmp_project: Project) -> None: tmp_project.write('src/a.cpp', 'int answer() { return 42; }') - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'mylib', 'version': '0.1.0', 'lib': { @@ -17,7 +17,7 @@ def test_self_referential_uses_fails(tmp_project: Project) -> None: def test_self_referential_uses_cycle_fails(tmp_project: Project) -> None: - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'mylib', 'version': @@ -43,7 +43,7 @@ def test_self_referential_uses_cycle_fails(tmp_project: Project) -> None: def test_self_referential_uses_for_libs_fails(tmp_project: Project) -> None: - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'mylib', 'version': '0.1.0', 'libs': [{ diff --git a/tests/test_basics.py b/tests/test_basics.py index 250bed06..a7d387e7 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -47,7 +47,7 @@ def test_simple_lib(tmp_project: Project) -> None: the manifest files will affect the output name. """ tmp_project.write('src/foo.cpp', 'int the_answer() { return 42; }') - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'test-project', 'version': '0.0.0', 'lib': { @@ -77,7 +77,7 @@ def test_error_enoent_toolchain(tmp_project: Project) -> None: def test_invalid_names(tmp_project: Project) -> None: - tmp_project.pkg_yaml = {'name': 'test', 'version': '1.2.3', 'dependencies': [{'dep': 'invalid name@1.2.3'}]} + tmp_project.bpt_yaml = {'name': 'test', 'version': '1.2.3', 'dependencies': [{'dep': 'invalid name@1.2.3'}]} with expect_error_marker('invalid-pkg-dep-name'): tmp_project.build() with expect_error_marker('invalid-pkg-dep-name'): @@ -85,8 +85,8 @@ def test_invalid_names(tmp_project: Project) -> None: with expect_error_marker('invalid-dep-shorthand'): tmp_project.bpt.build_deps(['invalid name@1.2.3']) - tmp_project.pkg_yaml['name'] = 'invalid name' - tmp_project.pkg_yaml['dependencies'] = [] + tmp_project.bpt_yaml['name'] = 'invalid name' + tmp_project.bpt_yaml['dependencies'] = [] with expect_error_marker('invalid-name'): tmp_project.build() with expect_error_marker('invalid-name'): @@ -100,26 +100,26 @@ def test_invalid_names(tmp_project: Project) -> None: def test_empty_with_pkg_json(tmp_project: Project) -> None: - tmp_project.pkg_yaml = TEST_PACKAGE + tmp_project.bpt_yaml = TEST_PACKAGE tmp_project.build() def test_empty_sdist_create(tmp_project: Project) -> None: - tmp_project.pkg_yaml = TEST_PACKAGE + tmp_project.bpt_yaml = TEST_PACKAGE tmp_project.pkg_create() assert tmp_project.build_root.joinpath('test-pkg@0.2.2~1.tar.gz').is_file(), \ 'The expected sdist tarball was not generated' def test_project_with_meta(tmp_project: Project) -> None: - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', 'license': 'MIT-1.2.3', } with expect_error_marker('invalid-spdx'): tmp_project.build() - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', 'license': 'MIT', # A valid license string @@ -157,7 +157,7 @@ def test_link_interdep(project_opener: ProjectOpener) -> None: }, }, }) - proj.pkg_yaml = { + proj.bpt_yaml = { 'name': 'test', 'version': '1.2.3', 'libs': [{ @@ -172,8 +172,8 @@ def test_link_interdep(project_opener: ProjectOpener) -> None: proj.build() # Update with a 'using' of the library that was required: - proj.pkg_yaml['libs'][0]['using'] = ['bar'] - print(proj.pkg_yaml) + proj.bpt_yaml['libs'][0]['using'] = ['bar'] + print(proj.bpt_yaml) # Build is okay now proj.build() diff --git a/tests/test_pkg.py b/tests/test_pkg.py index 07d3ed79..545a1c45 100644 --- a/tests/test_pkg.py +++ b/tests/test_pkg.py @@ -62,7 +62,7 @@ def test_sdist_unreadable_dir(bpt: BPTWrapper) -> None: def test_sdist_invalid_yml(tmp_project: Project) -> None: - tmp_project.write('pkg.yaml', '[[') + tmp_project.write('bpt.yaml', '[[') with error.expect_error_marker('package-yaml-parse-error'): tmp_project.pkg_create() @@ -70,7 +70,7 @@ def test_sdist_invalid_yml(tmp_project: Project) -> None: def test_pkg_search(tmp_crs_repo: CRSRepo, tmp_project: Project) -> None: with error.expect_error_marker('pkg-search-no-result'): tmp_project.bpt.run(['pkg', 'search', 'test-pkg', '-r', tmp_crs_repo.path]) - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'test-pkg', 'version': '0.1.2', } @@ -80,18 +80,18 @@ def test_pkg_search(tmp_crs_repo: CRSRepo, tmp_project: Project) -> None: def test_pkg_spdx(tmp_project: Project) -> None: - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', 'license': 'MIT', } tmp_project.pkg_create() - tmp_project.pkg_yaml['license'] = 'bogus' + tmp_project.bpt_yaml['license'] = 'bogus' with error.expect_error_marker('invalid-spdx'): tmp_project.pkg_create() dest_tgz = tmp_project.root / 'test.tgz' - tmp_project.pkg_yaml['license'] = 'MIT' + tmp_project.bpt_yaml['license'] = 'MIT' tmp_project.pkg_create(dest=dest_tgz) with tarfile.open(dest_tgz) as tgz: pkg_json = json.loads(tgz.extractfile('pkg.json').read()) diff --git a/tests/test_pkg_solve.py b/tests/test_pkg_solve.py index 273c83f1..0c9d40f5 100644 --- a/tests/test_pkg_solve.py +++ b/tests/test_pkg_solve.py @@ -57,7 +57,7 @@ def _render_pkg_version(name: str, version: str, item: _RepoPackageItem) -> Tree ] } return { - 'pkg.yaml': json.dumps(proj), + 'bpt.yaml': json.dumps(proj), 'libs': { lib_name: lib.get('content', {}) for lib_name, lib in item['libs'].items() # @@ -209,7 +209,7 @@ def test_solve_upgrade_pkg_version(make_quick_repo: QuickRepoFactory, tmp_projec } ) # yapf: enable - tmp_project.pkg_yaml = {'name': 'test-proj', 'version': '1.2.3', 'dependencies': ['foo@1.2.3 using main']} + tmp_project.bpt_yaml = {'name': 'test-proj', 'version': '1.2.3', 'dependencies': ['foo@1.2.3 using main']} tmp_project.write('src/file.cpp', '#include \n') with error.expect_error_marker('compile-failed'): tmp_project.build(repos=[repo.path]) diff --git a/tests/test_repo/test_repo.py b/tests/test_repo/test_repo.py index a7f11ffa..be4ca350 100644 --- a/tests/test_repo/test_repo.py +++ b/tests/test_repo/test_repo.py @@ -264,7 +264,7 @@ def test_repo_validate_interdep(tmp_crs_repo: CRSRepo, tmp_path: Path) -> None: def test_repo_validate_invalid_no_sibling(tmp_crs_repo: CRSRepo, tmp_project: Project) -> None: - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', 'libs': [{ @@ -306,7 +306,7 @@ def test_repo_no_use_invalid_pkg_version(tmp_crs_repo: CRSRepo, tmp_project: Pro db.execute(r'INSERT INTO crs_repo_packages(meta_json) VALUES(?)', [json.dumps(make_simple_crs('bar', '1.2.3', pkg_version=1))]) - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', 'lib': { diff --git a/tests/test_uses/dependents/basic_dependent/pkg.yaml b/tests/test_uses/dependents/basic_dependent/bpt.yaml similarity index 100% rename from tests/test_uses/dependents/basic_dependent/pkg.yaml rename to tests/test_uses/dependents/basic_dependent/bpt.yaml diff --git a/tests/test_uses/dependents/basic_test_dependent/pkg.yaml b/tests/test_uses/dependents/basic_test_dependent/bpt.yaml similarity index 100% rename from tests/test_uses/dependents/basic_test_dependent/pkg.yaml rename to tests/test_uses/dependents/basic_test_dependent/bpt.yaml diff --git a/tests/test_uses/dependents/multi_lib_dependent/pkg.yaml b/tests/test_uses/dependents/multi_lib_dependent/bpt.yaml similarity index 100% rename from tests/test_uses/dependents/multi_lib_dependent/pkg.yaml rename to tests/test_uses/dependents/multi_lib_dependent/bpt.yaml diff --git a/tests/test_uses/dependents/test_depends_but_regular_uses/pkg.yaml b/tests/test_uses/dependents/test_depends_but_regular_uses/bpt.yaml similarity index 100% rename from tests/test_uses/dependents/test_depends_but_regular_uses/pkg.yaml rename to tests/test_uses/dependents/test_depends_but_regular_uses/bpt.yaml diff --git a/tests/test_uses/test_uses_test.py b/tests/test_uses/test_uses_test.py index 5007a187..de4f20bc 100644 --- a/tests/test_uses/test_uses_test.py +++ b/tests/test_uses/test_uses_test.py @@ -91,7 +91,7 @@ def test_uses_sibling_lib(tmp_project: Project) -> None: }) # Missing the 'using' - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'testing', 'version': '1.2.3', 'libs': [{ @@ -106,7 +106,7 @@ def test_uses_sibling_lib(tmp_project: Project) -> None: tmp_project.build() # Now add the missing 'using' - tmp_project.pkg_yaml = { + tmp_project.bpt_yaml = { 'name': 'testing', 'version': '1.2.3', 'libs': [{ diff --git a/tests/test_uses/the_test_dependency/pkg.yaml b/tests/test_uses/the_test_dependency/bpt.yaml similarity index 100% rename from tests/test_uses/the_test_dependency/pkg.yaml rename to tests/test_uses/the_test_dependency/bpt.yaml diff --git a/tests/test_uses/the_test_lib/pkg.yaml b/tests/test_uses/the_test_lib/bpt.yaml similarity index 100% rename from tests/test_uses/the_test_lib/pkg.yaml rename to tests/test_uses/the_test_lib/bpt.yaml diff --git a/tests/test_uses/unbuildable/pkg.yaml b/tests/test_uses/unbuildable/bpt.yaml similarity index 100% rename from tests/test_uses/unbuildable/pkg.yaml rename to tests/test_uses/unbuildable/bpt.yaml diff --git a/tests/test_uses/with_bad_test_dep/pkg.yaml b/tests/test_uses/with_bad_test_dep/bpt.yaml similarity index 100% rename from tests/test_uses/with_bad_test_dep/pkg.yaml rename to tests/test_uses/with_bad_test_dep/bpt.yaml diff --git a/tests/test_uses/with_transitive_bad_test_dep/pkg.yaml b/tests/test_uses/with_transitive_bad_test_dep/bpt.yaml similarity index 100% rename from tests/test_uses/with_transitive_bad_test_dep/pkg.yaml rename to tests/test_uses/with_transitive_bad_test_dep/bpt.yaml diff --git a/tests/use-spdlog/project/pkg.yaml b/tests/use-spdlog/project/bpt.yaml similarity index 100% rename from tests/use-spdlog/project/pkg.yaml rename to tests/use-spdlog/project/bpt.yaml diff --git a/tests/use-spdlog/use_spdlog_test.py b/tests/use-spdlog/use_spdlog_test.py index 7af5e264..e6c43f1c 100644 --- a/tests/use-spdlog/use_spdlog_test.py +++ b/tests/use-spdlog/use_spdlog_test.py @@ -41,7 +41,7 @@ def test_get_build_use_spdlog(project_opener: ProjectOpener, toolchain_path: Pat def test_invalid_uses_specifier(project_opener: ProjectOpener, toolchain_path: Path, repo_with_spdlog: CRSRepo) -> None: proj = project_opener.open('project') - proj.pkg_yaml = { + proj.bpt_yaml = { 'name': 'test', 'version': '0.0.0', 'dependencies': ['spdlog@1.4.2 using no-such-library'], diff --git a/tools/bpt_ci/tasks.py b/tools/bpt_ci/tasks.py index c95f3fd4..c3363ec5 100644 --- a/tools/bpt_ci/tasks.py +++ b/tools/bpt_ci/tasks.py @@ -204,7 +204,7 @@ async def __get_catch2() -> Path: into.with_suffix('.tmp').rename(into) proj_dir = into / '_proj' proj_dir.mkdir(exist_ok=True) - proj_dir.joinpath('pkg.yaml').write_text( + proj_dir.joinpath('bpt.yaml').write_text( json.dumps({ 'name': 'catch2', @@ -286,7 +286,7 @@ async def _repo_import_pkg(bpt: BPTWrapper, pkg: str, repo_dir: Path) -> None: pid = f'{name}@{ver}' pulled = paths.PREBUILT_DIR / 'ci-repo' / pid assert pulled.is_dir(), pid - pulled.joinpath('pkg.yaml').write_text( + pulled.joinpath('bpt.yaml').write_text( json.dumps({ 'name': name, 'version': ver, diff --git a/tools/bpt_ci/testing/fixtures.py b/tools/bpt_ci/testing/fixtures.py index 229ca932..9e106455 100644 --- a/tools/bpt_ci/testing/fixtures.py +++ b/tools/bpt_ci/testing/fixtures.py @@ -231,16 +231,16 @@ def __init__(self, dirpath: Path, bpt: BPTWrapper) -> None: self.build_root = dirpath / '_build' @property - def pkg_yaml(self) -> PkgYAML: + def bpt_yaml(self) -> PkgYAML: """ - Get/set the content of the ``pkg.yaml`` file for the project. + Get/set the content of the ``bpt.yaml`` file for the project. """ - dat = json.loads(self.root.joinpath('pkg.yaml').read_text()) - return cast(PkgYAML, _WritebackData(self.root.joinpath('pkg.yaml'), dat, dat)) + dat = json.loads(self.root.joinpath('bpt.yaml').read_text()) + return cast(PkgYAML, _WritebackData(self.root.joinpath('bpt.yaml'), dat, dat)) - @pkg_yaml.setter - def pkg_yaml(self, data: PkgYAML) -> None: - self.root.joinpath('pkg.yaml').write_text(json.dumps(data, indent=2)) + @bpt_yaml.setter + def bpt_yaml(self, data: PkgYAML) -> None: + self.root.joinpath('bpt.yaml').write_text(json.dumps(data, indent=2)) def lib(self, name: str) -> Library: return Library(name, self.root / f'libs/{name}') From 9a1b15b3020c8b8e026afac20eb1bec9f8feea8a Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 14 Apr 2022 22:56:17 -0600 Subject: [PATCH 10/62] Remove unused "pkg ls" command --- src/bpt/cli/options.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 6cb3dcd5..27a52a8e 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -276,10 +276,6 @@ struct setup { .valname = "", .action = put_into(opts.pkg.subcommand), }); - pkg_group.add_parser({ - .name = "ls", - .help = "List locally available packages", - }); setup_pkg_create_cmd(pkg_group.add_parser({ .name = "create", .help = "Create a source distribution archive of a project", From 572b2c4484eef89b03e1d64e4aa4494dfc3c89b5 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 14 Apr 2022 22:58:39 -0600 Subject: [PATCH 11/62] Revive build_lib_with_failing_test_dep test --- tests/test_uses/test_uses_test.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/test_uses/test_uses_test.py b/tests/test_uses/test_uses_test.py index de4f20bc..267a7b48 100644 --- a/tests/test_uses/test_uses_test.py +++ b/tests/test_uses/test_uses_test.py @@ -14,17 +14,17 @@ def ut_repo(crs_repo_factory: CRSRepoFactory, test_parent_dir: Path) -> CRSRepo: return repo -## TODO: Do not build test libs if we are not building tests -# def test_build_lib_with_failing_test_dep(project_opener: ProjectOpener, ut_repo: CRSRepo) -> None: -# proj = project_opener.open('with_bad_test_dep') -# # If we disable tests, then we won't try to build the test libraries, and -# # therefore won't hit the compilation error -# proj.build(with_tests=False, repos=[ut_repo.path]) -# # Compiling with tests enabled produces an error -# with error.expect_error_marker('compile-failed'): -# proj.build(with_tests=True) -# # Check that nothing changed spuriously -# proj.build(with_tests=False) +# TODO: Do not build test libs if we are not building tests +def test_build_lib_with_failing_test_dep(project_opener: ProjectOpener, ut_repo: CRSRepo) -> None: + proj = project_opener.open('with_bad_test_dep') + # If we disable tests, then we won't try to build the test libraries, and + # therefore won't hit the compilation error + proj.build(with_tests=False, repos=[ut_repo.path]) + # Compiling with tests enabled produces an error + with error.expect_error_marker('compile-failed'): + proj.build(with_tests=True, repos=[ut_repo.path]) + # Check that nothing changed spuriously + proj.build(with_tests=False, repos=[ut_repo.path]) def test_build_lib_with_failing_transitive_test_dep(project_opener: ProjectOpener, ut_repo: CRSRepo) -> None: From 28513c81f3d122550a58c81e3d55daacc556331c Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Fri, 15 Apr 2022 00:19:04 -0600 Subject: [PATCH 12/62] Implement selective library building: Only those required for the root sdist are built --- src/bpt/build/builder.cpp | 100 +++++++++++++++--- src/bpt/build/builder.hpp | 3 + src/bpt/cli/cmd/build_common.cpp | 16 ++- src/bpt/cli/cmd/build_common.hpp | 2 + src/bpt/cli/cmd/build_deps.cpp | 6 +- tests/test_uses/partially_buildable/bpt.yaml | 7 ++ .../can_build/src/can_build/header.hpp | 5 + .../can_build/src/can_build/source.cpp | 3 + .../cannot_build/src/fail.cpp | 1 + tests/test_uses/test_uses_test.py | 31 +++++- 10 files changed, 158 insertions(+), 16 deletions(-) create mode 100644 tests/test_uses/partially_buildable/bpt.yaml create mode 100644 tests/test_uses/partially_buildable/can_build/src/can_build/header.hpp create mode 100644 tests/test_uses/partially_buildable/can_build/src/can_build/source.cpp create mode 100644 tests/test_uses/partially_buildable/cannot_build/src/fail.cpp diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index 4e82dfae..e3b480ef 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -41,6 +43,15 @@ void log_failure(const test_failure& fail) { } } +///? XXX: This library activating method is a poor hack to ensure only libraries that are used by +///? the main libraries are actually built. +/// TODO: Make this less ugly. +struct lib_prep_info { + const sdist_target& sdt; + const crs::library_info& lib; + const crs::package_info& pkg; +}; + library_plan prepare_library(const sdist_target& sdt, const crs::library_info& lib, const crs::package_info& pkg_man) { @@ -52,19 +63,84 @@ library_plan prepare_library(const sdist_target& sdt, return library_plan::create(sdt.sd.path, pkg_man, lib, std::move(lp)); } -package_plan prepare_one(const sdist_target& sd) { - auto& man = sd.sd.pkg; - package_plan pkg{man.id.name.str}; - for (auto& lib : man.libraries) { - pkg.add_library(prepare_library(sd, lib, man)); - } - return pkg; -} - -build_plan prepare_build_plan(const std::vector& sdists) { +build_plan prepare_build_plan(neo::ranges::range_of auto&& sdists) { build_plan plan; - for (const auto& sd_target : sdists) { - plan.add_package(prepare_one(sd_target)); + // First generate a mapping of all libraries + std::map all_libs; + // Keep track of which libraries we want to build: + std::set libs_to_build; + // Iterate all loaded sdists: + for (const sdist_target& sdt : sdists) { + for (const auto& lib : sdt.sd.pkg.libraries) { + const lib_prep_info& lpi = // + all_libs + .emplace(lm::usage(sdt.sd.pkg.id.name.str, lib.name.str), + lib_prep_info{ + .sdt = sdt, + .lib = lib, + .pkg = sdt.sd.pkg, + }) + .first->second; + // If the sdist_build_params wants libraries, activate them now: + if (ranges::contains(sdt.params.build_libraries, lib.name)) { + libs_to_build.emplace(&lpi); + } + } + } + // Recursive library activator: + std::function activate_more = [&](const lib_prep_info& inf) { + auto add_deps = [&](auto&& deps) { + for (const auto& dep : deps) { + // We should never reach this point with implicit usages + neo_assert(invariant, + dep.uses.template is(), + "An implicit-using slipped through to the builder", + inf.lib.name, + dep.name); + for (const auto& use : dep.uses.template as().uses) { + // All libraries that we are using must have been loaded into the builder + // (i.e. by the package dependency solver) + auto found = all_libs.find(lm::usage{dep.name.str, use.str}); + neo_assert(invariant, + found != all_libs.end(), + "Failed to find a dependency library for build activation", + inf.lib.name, + dep.name, + use); + bool did_add = libs_to_build.emplace(&found->second).second; + if (did_add) { + // Recursively activate more libraries used by this library. + activate_more(found->second); + } + } + } + }; + add_deps(inf.lib.dependencies); + if (!inf.sdt.params.build_tests) { + return; + } + // We also need to build test dependencies + add_deps(inf.lib.test_dependencies); + }; + // Now actually begin activation: + for (auto info : libs_to_build) { + activate_more(*info); + } + // Create package plans for each library and the package it owns: + std::map pkg_plans; + for (auto lp : libs_to_build) { + package_plan pkg{lp->sdt.sd.pkg.id.name.str}; + auto cur = pkg_plans.find(lp->sdt.sd.pkg.id.name); + if (cur == pkg_plans.end()) { + cur = pkg_plans + .emplace(lp->sdt.sd.pkg.id.name, package_plan{lp->sdt.sd.pkg.id.name.str}) + .first; + } + cur->second.add_library(prepare_library(lp->sdt, lp->lib, lp->pkg)); + } + // Add all the packages to the plan: + for (const auto& pair : pkg_plans) { + plan.add_package(std::move(pair.second)); } return plan; } diff --git a/src/bpt/build/builder.hpp b/src/bpt/build/builder.hpp index e0f62c91..469f22ee 100644 --- a/src/bpt/build/builder.hpp +++ b/src/bpt/build/builder.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace bpt { @@ -22,6 +23,8 @@ struct sdist_build_params { bool build_apps = false; /// Whether to enable build warnings bool enable_warnings = false; + /// The libraries in this source distribution that we must build + std::vector build_libraries; }; /** diff --git a/src/bpt/cli/cmd/build_common.cpp b/src/bpt/cli/cmd/build_common.cpp index b87d4ddd..096ac2ae 100644 --- a/src/bpt/cli/cmd/build_common.cpp +++ b/src/bpt/cli/cmd/build_common.cpp @@ -45,6 +45,7 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { .run_tests = opts.build.want_tests, .build_apps = opts.build.want_apps, .enable_warnings = !opts.disable_warnings, + .build_libraries = {}, }; auto cache = open_ready_cache(opts); @@ -74,16 +75,25 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { auto sln = bpt::solve(meta_db, crs_deps); for (auto&& pkg : sln) { - auto dep_meta = fetch_cache_load_dependency(cache, pkg, builder, "_deps"); + auto dep_meta + = fetch_cache_load_dependency(cache, + pkg, + false /* Do not mark libraries to be built */, + builder, + "_deps"); resolve_implicit_usages(proj_sd.pkg, dep_meta); } } + + extend(main_params.build_libraries, + proj_sd.pkg.libraries | std::views::transform(&crs::library_info::name)); builder.add(proj_sd, main_params); return builder; } crs::package_info bpt::cli::fetch_cache_load_dependency(crs::cache& cache, crs::pkg_id const& pkg, + bool build_all_libs, bpt::builder& builder, path_ref subdir_base) { bpt_log(debug, "Loading package '{}' for build", pkg.to_string()); @@ -95,6 +105,10 @@ crs::package_info bpt::cli::fetch_cache_load_dependency(crs::cache& cache bpt::sdist sd{crs_meta, local_dir}; sdist_build_params params; + if (build_all_libs) { + extend(params.build_libraries, + crs_meta.libraries | std::views::transform(&crs::library_info::name)); + } params.subdir = subdir_base / sd.pkg.id.to_string(); builder.add(sd, params); return crs_meta; diff --git a/src/bpt/cli/cmd/build_common.hpp b/src/bpt/cli/cmd/build_common.hpp index 0bd3182f..495d144b 100644 --- a/src/bpt/cli/cmd/build_common.hpp +++ b/src/bpt/cli/cmd/build_common.hpp @@ -32,11 +32,13 @@ int handle_build_error(std::function); * * @param cache * @param pkg + * @param build_all_libs If `true`, all libraries will be marked for building, otherwise none * @param b * @return crs::package_info */ crs::package_info fetch_cache_load_dependency(crs::cache& cache, const crs::pkg_id& pkg, + bool build_all_libs, builder& b, const std::filesystem::path& subdir_base); diff --git a/src/bpt/cli/cmd/build_deps.cpp b/src/bpt/cli/cmd/build_deps.cpp index fc7ad840..7280db07 100644 --- a/src/bpt/cli/cmd/build_deps.cpp +++ b/src/bpt/cli/cmd/build_deps.cpp @@ -55,7 +55,11 @@ static int _build_deps(const options& opts) { auto sln = bpt::solve(cache.db(), all_deps); for (auto&& pkg : sln) { - fetch_cache_load_dependency(cache, pkg, builder, "."); + fetch_cache_load_dependency(cache, + pkg, + true /* Build all libraries in the dependency */, + builder, + "."); } builder.build(params); diff --git a/tests/test_uses/partially_buildable/bpt.yaml b/tests/test_uses/partially_buildable/bpt.yaml new file mode 100644 index 00000000..466a1ce3 --- /dev/null +++ b/tests/test_uses/partially_buildable/bpt.yaml @@ -0,0 +1,7 @@ +name: partially_buildable +version: 0.1.0 +libs: + - path: can_build + name: can_build + - path: cannot_build + name: cannot_build diff --git a/tests/test_uses/partially_buildable/can_build/src/can_build/header.hpp b/tests/test_uses/partially_buildable/can_build/src/can_build/header.hpp new file mode 100644 index 00000000..2a66be3a --- /dev/null +++ b/tests/test_uses/partially_buildable/can_build/src/can_build/header.hpp @@ -0,0 +1,5 @@ +#pragma once + +// Just an empty header + +constexpr int CAN_BUILD_ZERO = 0; \ No newline at end of file diff --git a/tests/test_uses/partially_buildable/can_build/src/can_build/source.cpp b/tests/test_uses/partially_buildable/can_build/src/can_build/source.cpp new file mode 100644 index 00000000..ed2cfd77 --- /dev/null +++ b/tests/test_uses/partially_buildable/can_build/src/can_build/source.cpp @@ -0,0 +1,3 @@ +#include "./header.hpp" + +static_assert(CAN_BUILD_ZERO == 0, "Check that zero is zero"); diff --git a/tests/test_uses/partially_buildable/cannot_build/src/fail.cpp b/tests/test_uses/partially_buildable/cannot_build/src/fail.cpp new file mode 100644 index 00000000..bd8f801a --- /dev/null +++ b/tests/test_uses/partially_buildable/cannot_build/src/fail.cpp @@ -0,0 +1 @@ +#error "This file will never compile" \ No newline at end of file diff --git a/tests/test_uses/test_uses_test.py b/tests/test_uses/test_uses_test.py index 267a7b48..3df4d52c 100644 --- a/tests/test_uses/test_uses_test.py +++ b/tests/test_uses/test_uses_test.py @@ -9,7 +9,7 @@ @pytest.fixture(scope='module') def ut_repo(crs_repo_factory: CRSRepoFactory, test_parent_dir: Path) -> CRSRepo: repo = crs_repo_factory('uses-test') - names = ('the_test_dependency', 'the_test_lib', 'unbuildable', 'with_bad_test_dep') + names = ('the_test_dependency', 'the_test_lib', 'unbuildable', 'with_bad_test_dep', 'partially_buildable') repo.import_((test_parent_dir / name for name in names)) return repo @@ -118,4 +118,31 @@ def test_uses_sibling_lib(tmp_project: Project) -> None: 'using': ['main'] }] } - tmp_project.build() \ No newline at end of file + tmp_project.build() + + +def test_build_partial_dep(tmp_project: Project, ut_repo: CRSRepo) -> None: + fs.render_into( + tmp_project.root, { + 'src': { + 'use-lib.cpp': + r''' + #include + + int main() { + return CAN_BUILD_ZERO; + } + ''', + }, + }) + + tmp_project.bpt_yaml = { + 'name': 'test-user', + 'version': '1.2.3', + 'dependencies': ['partially_buildable@0.1.0 using can_build'], + } + tmp_project.build(repos=[ut_repo.path]) + + tmp_project.bpt_yaml['dependencies'] = ['partially_buildable@0.1.0 using can_build, cannot_build'] + with error.expect_error_marker('compile-failed'): + tmp_project.build(repos=[ut_repo.path]) From 7213fe3e59e36a5bbafdfe08fc8ab93b40b6e814 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Tue, 19 Apr 2022 23:42:29 -0600 Subject: [PATCH 13/62] Major docs updates --- docs/conf.py | 27 +- docs/crs/dependencies.rst | 5 + docs/crs/index.rst | 365 +++++++++++++++++++++ docs/crs/libraries.rst | 421 +++++++++++++++++++++++++ docs/crs/names.rst | 56 ++++ docs/crs/packages.rst | 57 ++++ docs/crs/versions.rst | 49 +++ docs/guide/cli/build-deps.rst | 24 ++ docs/guide/cli/build.rst | 30 ++ docs/guide/cli/compile-file.rst | 25 ++ docs/guide/cli/index.rst | 98 ++++++ docs/guide/cli/install-yourself.rst | 34 ++ docs/guide/cli/new.rst | 20 ++ docs/guide/cli/opt-jobs.rst | 7 + docs/guide/cli/opt-no-default-repo.rst | 6 + docs/guide/cli/opt-out.rst | 6 + docs/guide/cli/opt-project.rst | 5 + docs/guide/cli/opt-repo-sync.rst | 26 ++ docs/guide/cli/opt-toolchain.rst | 6 + docs/guide/cli/opt-tweaks-dir.rst | 4 + docs/guide/cli/opt-use-repo.rst | 8 + docs/guide/cli/pkg.rst | 85 +++++ docs/guide/cli/repo-common-args.rst | 3 + docs/guide/cli/repo.rst | 146 +++++++++ docs/guide/cli/terms.rst | 28 ++ docs/guide/filesystem.rst | 181 +++++++++++ docs/guide/index.rst | 13 +- docs/guide/terms.rst | 106 +++++++ docs/guide/toolchains.rst | 1 + docs/howto/cmake.rst | 23 +- docs/howto/deps.rst | 98 ++---- docs/index.rst | 9 + docs/static/styles.css | 24 ++ docs/tut/hello-test.rst | 31 +- docs/tut/hello-world.rst | 198 +++++++----- docs/tut/install.rst | 38 ++- 36 files changed, 2072 insertions(+), 191 deletions(-) create mode 100644 docs/crs/dependencies.rst create mode 100644 docs/crs/index.rst create mode 100644 docs/crs/libraries.rst create mode 100644 docs/crs/names.rst create mode 100644 docs/crs/packages.rst create mode 100644 docs/crs/versions.rst create mode 100644 docs/guide/cli/build-deps.rst create mode 100644 docs/guide/cli/build.rst create mode 100644 docs/guide/cli/compile-file.rst create mode 100644 docs/guide/cli/index.rst create mode 100644 docs/guide/cli/install-yourself.rst create mode 100644 docs/guide/cli/new.rst create mode 100644 docs/guide/cli/opt-jobs.rst create mode 100644 docs/guide/cli/opt-no-default-repo.rst create mode 100644 docs/guide/cli/opt-out.rst create mode 100644 docs/guide/cli/opt-project.rst create mode 100644 docs/guide/cli/opt-repo-sync.rst create mode 100644 docs/guide/cli/opt-toolchain.rst create mode 100644 docs/guide/cli/opt-tweaks-dir.rst create mode 100644 docs/guide/cli/opt-use-repo.rst create mode 100644 docs/guide/cli/pkg.rst create mode 100644 docs/guide/cli/repo-common-args.rst create mode 100644 docs/guide/cli/repo.rst create mode 100644 docs/guide/cli/terms.rst create mode 100644 docs/guide/filesystem.rst create mode 100644 docs/guide/terms.rst create mode 100644 docs/static/styles.css diff --git a/docs/conf.py b/docs/conf.py index 976c3026..c1d297eb 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Refer: http://www.sphinx-doc.org/en/master/config -import os +from sphinx.application import Sphinx from pathlib import Path from typing import Any import sys @@ -11,7 +11,7 @@ # -- Project information ----------------------------------------------------- project = 'bpt' -copyright = '2020, vector-of-bool' +copyright = '2022' author = 'vector-of-bool' # The short X.Y version @@ -43,19 +43,19 @@ autodoc_typehints = 'none' # -- Options for HTML output ------------------------------------------------- -html_theme = 'nature' +html_theme = 'pyramid' html_theme_options = {} -html_static_path = [] +html_static_path = ['static'] html_sidebars = {} -hoverxref_roles = [ - 'term', - 'ref', -] hoverxref_role_types = { 'term': 'tooltip', 'ref': 'tooltip', + 'envvar': 'tooltip', + 'option': 'tooltip', } + +hoverxref_roles = list(hoverxref_role_types.keys()) hoverxref_auto_ref = True hoverxref_mathjax = True @@ -72,9 +72,12 @@ def intercept_copy_asset(path: str, dest: str, context: Any) -> None: hoverxref.extension.copy_asset = intercept_copy_asset rst_prolog = r''' -.. |bpt| replace:: :literal:`bpt` +.. role:: bpt-name(literal) + :class: bpt-name + +.. |bpt| replace:: :bpt-name:`bpt` ''' -if os.environ.get('GEN_FOR_HUGO'): - templates_path.append('.') - html_theme = 'basic' + +def setup(app: Sphinx): + app.add_css_file('styles.css') diff --git a/docs/crs/dependencies.rst b/docs/crs/dependencies.rst new file mode 100644 index 00000000..22aaa3e0 --- /dev/null +++ b/docs/crs/dependencies.rst @@ -0,0 +1,5 @@ +############ +Dependencies +############ + +CRS dependencies specify packages, libraries, and version. diff --git a/docs/crs/index.rst b/docs/crs/index.rst new file mode 100644 index 00000000..9bfbe3db --- /dev/null +++ b/docs/crs/index.rst @@ -0,0 +1,365 @@ +######################## +The CRS Packaging Format +######################## + +.. highlight:: javascript + +.. |version| replace:: :hoverxreftooltip:`version ` + +.. |name| replace:: :doc:`name ` + +.. default-role:: term + +`CRS`, an initialism for ":strong:`C`\ ompile-:strong:`R`\ eady :strong:`S`\ +ource", is a package format with an emphasis on simplicity and embeddability. A +`CRS package` is so-called "compile-ready" because it contains package source +files that do not require preparation, configuration, generation, or tweaking +before being given to a compiler. + +.. note:: + + The `CRS` format is intended to be portable and not directly tied to |bpt| + itself. + +Topics +###### + +.. toctree:: + + packages + libraries + dependencies + versions + names + +Base Concepts +############# + +Briefly, `CRS` concerns itself with the following high-level concepts: + +.. glossary:: + + CRS + + An acronym for :strong:`C`\ ompile-\ :strong:`R`\ eady :strong:`S`\ ource. + CRS is a set of file formats and `JSON` schemas that describe a way to + destribute software in source-code format, ready to be given to any + compatible compiler without further configuration or code generation. + + .. seealso:: :doc:`index` + + CRS package + + A CRS package is the unit of distribution in `CRS`. A package has a |name| + and a |version| and contains one or more `CRS libraries `. + + .. seealso:: :doc:`The documentation page about packages ` + + CRS library + + A CRS library is the smallest consumable unit in a `CRS package`. A package + can have one or more libraries, but a library can only belong to one + package. Each library within a single package must have a unique |name|. A + library can have some number of `CRS dependencies `, and can + "`use `" other libraries within the same package. + + .. seealso:: :doc:`The documentation page about libraries ` + + CRS dependency + + A CRS dependency is associated with a `CRS library` within a `CRS package`. + A dependency names a package, one or more libraries within that package, and + one or more compatible version ranges. + + .. seealso:: + + :doc:`The documentation page about dependencies ` + + +Storage Format +############## + +A CRS package can be represented in any system that allows heirarchical data +storage with named files and directories. This may be a regular directory on +disk, a Zip archive, a Tar archive, a database table, or even something as +simple as a single large `JSON` document. + + +.. _crs.json: + +``crs.json`` +************ + +At the root of the package must be a valid `JSON` document named ``crs.json``. +This file encodes all of the metadata in the package. + +At any point in the `JSON` object, if any `JSON` object key string begins with +the substring "``_comment``", then content of that object entry is to be ignored +for validating the `JSON` data. + +The basic interface of ``crs.json`` looks as below: + +.. code-block:: javascript + + interface CRSJSON { + "schema-version": 1, + name: NameString, + version: VersionString, + "pkg-version": integer, + libraries: CRSLibrary[], + meta?: { + [key: string]: unknown + }, + extra?: null | { + [key: string]: unknown + }, + } + + interface CRSLibrary { + name: NameString, + path: string, + using: NameString[], + dependencies: CRSDependency[], + "test-dependencies": CRSDependency[], + } + + interface CRSDependency { + name: NameString, + using: NameString, + versions: VersionRange[], + } + + interface VersionRange { + low: VersionString, + high: VersionString, + } + +Where "``NameString``" is a string that is a valid :doc:`CRS name ` and +"``VersionString``" is a string that is a valid +:hoverxref:`Semantic Version string `. + +The root of this JSON data must be a JSON object with the following *required* +keys: + +``schema-version`` +================== + +An integer encoding the version of the CRS metadata itself. For this +documentation, this number must be ``1``. + +If the ``schema-version`` is greater than the version supported by the system, +the package must be rejected as invalid. + +``name`` +======== + +A string. Specifies the name of a package. :doc:`Must be a valid name. ` + +``version`` +=========== + +A string. Specifies the version of the package. Must be a valid +:hoverxref:`Semantic Version string `. + +``pkg-version`` +=============== + +An integer. Specifies the version of the package itself (not related to the +version of the software that is packaged). + +If the ``pkg-version`` is not a positive non-zero whole integer, the package is +invalid. + +``libraries`` +============= + +An array of library definitions for the package. Refer to: :ref:`crs.libraries`. +If any of the libraries in the array are invalid, the entire package is invalid. + +``meta`` +======== + +An optional JSON object containing metadata attributes for the package intended +for human consumption. + +``extra`` +========= + +An optional JSON object or ``null`` that encodes additional tool-specific +attributes for the package. + +.. _crs.libraries: + +Libraries +********* + +In :ref:`crs.json`, the ``libraries`` property must be an array of CRS library +JSON objects. + +Each object in that array defines a library for the package. Each object must +contain the following properties: + + +``name`` +======== + +The name of the library. :doc:`Must be a valid name. ` + +No two libraries within a single package may share a name. + + +``path`` +======== + +The path to the library root. This must be a valid UTF-8 POSIX-style relative +filepath using forward-slash "``/``" (solidus) directory separators. The path +may not contain any backslash "``\``" characters. + +A library path must be normalized and validated according to the following +rules: + +1. If the first character in the path is a forward-slash, the path is invalid + (absolute paths are not allowed). +2. For every sequence of two or more forward-slashes in the path string, replace + the sequence with a single forward-slash. +3. Remove a final forward-slash in the path string, if present. +4. Split the path string on forward-slashes into a list of *component* strings. +5. Remove every component from the array that is a single ASCII dot "``.``". +6. For each *component* in the path string that is a dot-dot "``..``": + + 1. If the dot-dot component is the first component in the component list, the + path is invalid (The path attempts to reach outside of the CRS package). + 2. Delete the dot-dot component and the component preceeding it in the array. + +7. All remaining path components must also be valid :doc:`CRS names `, except + that they may begin with an ASCII digit. Otherwise the path is invalid. +8. Join the component array with forward-slashes in-between each component. This + is the new path. +9. If the path is an empty string, the path is "``.``". + +After normalizing the library's path, no two libraries may have the same path. +Some platforms may place additional restrictions on library paths. + + +``using`` +========= + +A list of :doc:`names` of other libraries within the same package. Each string must +correspond to the ``name`` property on some other library in the package. A +library cannot "use" itself. The chain of ``using`` should form a acyclic graph. +If a ``using`` string names a non-existent library, or if there is a cycle in +the ``using`` graph, the entire package is invalid. + + +``dependencies`` +================ + +An array of `CRS dependency` objects. + +This array specifies the dependencies of the library within the package. + + +``test-dependencies`` +===================== + +An array of `CRS dependency` objects. + +This array specifies the test-only dependencies of the library within the +package. + + +Dependencies +************ + +A CRS dependency identifies a package by name, one or more version ranges, and +some set of used-libraries. A dependency is associated with a +`library ` within a package, and not with the package as a whole. + +A CRS dependency is specified as a JSON object with the following required +properties: + + +``name`` +======== + +The name of a package which is being depended-upon. +:doc:`Must be a valid name. ` + + +``using`` +========= + +An array of |name| strings identifying libraries within the depended-upon +package to be used by the library that contains this dependency. + + +``versions`` +============ + +An array of one or more *version range* objects. Each JSON object must contain +the following properties: + +``low`` + The minimum version of the range. Must be a valid + :hoverxref:`Semantic Version string `. + +``high`` + The maximum version of the range, exclusive. Must be a valid + :hoverxref:`Semantic Version string `. + + +Range Semantics +*************** + +Versions should be compared using the version ordering specified by +:ref:`SemVer`. + +For the purpose of version comparison, a synthesized version number "synth-high" +refers to the version specified by ``high`` with an additional +lowest-possible-precedence prerelease identifier attached. It is impossible to +spell this synthesized semantic version number as a valid string, but it is +required to obtain half-open range semantics on version ranges. For purposes of +examples here, this lowest-possible-precedence prerelease identifier will be +represented as a percent-symbol "``%``". + +If given a version ``V`` and a ``low`` and ``high`` range, ``V`` is considered +to be within the version range if it is greater-than or equal-to ``low``, and +less-than "synth-high". + + +Range Comparison Example +======================== + +Suppose a version range is provided:: + + { + "low": "2.8.0", + "high": "3.0.0" + } + +and the following versions are available: + +- ``1.2.6`` +- ``2.5.6`` +- ``2.7.5`` +- ``2.8.0-beta.1`` +- ``3.0.0-alpha`` +- ``3.1.0`` + +It is easy to see that ``1.2.6``, ``2.5.6``, and ``2.7.5`` are too old, as they +compare less-than the ``low`` version. The ``3.1.0`` version is greater-than the +``high`` version, so it is also not within the range. + +The ``2.8.0-beta.1`` version is less-than our low ``2.8.0`` requirement, since +prerelease versions are strictly less-than a non-prerelease with the same +version number components. + +The ``3.0.0-alpha`` version *is* within the half-open version range +``[2.8.0, 3.0.0)``, because ``3.0.0-alpha`` is *less-than* ``3.0.0``. However, +selecting this version to satisfy the range would be very surprising and +unlikely to be what the user wanted. For this reason, the synthesized prerelease +"high" version ``3.0.0-%`` is used for the range comparison. The imaginary +"``%``" prerelease identifier is strictly less than all other possible +prerelease identifiers. For this reason, ``3.0.0-alpha`` is *not* within the +half-open version range ``[2.8.0, 3.0.0-%)``, and therefore does not satisfy the +dependency version range JSON object provided. diff --git a/docs/crs/libraries.rst b/docs/crs/libraries.rst new file mode 100644 index 00000000..e6c78d4d --- /dev/null +++ b/docs/crs/libraries.rst @@ -0,0 +1,421 @@ +######### +Libraries +######### + +.. |name| replace:: :doc:`name ` +.. |package| replace:: :term:`package ` +.. |library| replace:: :term:`library ` +.. |libraries| replace:: :term:`libraries ` +.. |dependencies| replace:: :term:`dependencies ` +.. |dependency| replace:: :term:`dependency ` + +A CRS library is the smallest consumable unit in a |package|. A package can have +one or more libraries, but a library can only belong to one package. Each +library within a single package must have a unique |name|. A library can have +some number of |dependencies|, and can "use" other libraries within the same +package. + +.. default-role:: term + + +Terms +##### + +.. glossary:: + + library name + + The name of the library. The name must be unique within the containing + `CRS package`, and must be a valid |name|. + + library path + + The "path" of a library is a POSIX-style `relative filepath` (relative to + the root of the containing package). The path must name a `library root` + within the package. + + library internal usages + + Each |library| in a |package| can declare that it "`uses `" + other libraries in that same |package|. + + .. seealso:: `Internal Usages`_ + + library external dependencies + + Each library in a |package| can declare a unique set of |dependencies| and + `library usages ` on libraries from other packages. + + .. seealso:: `External Dependencies`_ + + library usage + .. |def-library-usage| replace:: + + Library usage is a one-way relationship between a + `user library ` and a `used library `. The + *user* library is able to reference and make use all entities publicly + exposed by the *used* library, including headers, classes, functions, + modules, and macros. Library usage also *transitive*. + + |def-library-usage| + + If :math:`A` uses :math:`B`, and :math:`B` uses :math:`C`, then :math:`A` + has a *transitive* usage of :math:`C`. + + A `library usage` may identify a library within the same |package| as the + `library user`, or may specify a library in a |dependency| package. + + When library :math:`A` uses library :math:`B`, :math:`B`\ 's + `public header root` is added as a `header search path` for :math:`A`, and + any programs in :math:`A` will be linked with the `public translation units` + for :math:`B`. + + Library usage must never form a cycle where a library can (transitively) + "use itself". + + library user + + The *users* of a |library| :math:`L` are the libraries that declare a + `library usage` on :math:`L`. + + |def-library-usage| + + used-library + + The |libraries| *used-by* :math:`L` are the libraries upon which :math:`L` + declares a `library usage`. :math:`L` becomes a "`library user`" of the + libraries that it uses. + + |def-library-usage| + + library root + + The `directory` in which the source files of a single |library| reside. + Contains the ``src/`` and ``include/`` `directories ` for a |library|. + + .. seealso:: :ref:`The documentation on library roots ` + + source root + + A subdirectories of the `library root` that contain the source files for a + the library (including headers). + + .. seealso:: `Source Roots`_ + + source code + + The code for a program written in some programming language. + + source file + + Source files are regular (non-`directory`) files that contain code of some + programming language. + + header file + + A header file (or just "*header*") is kind of `source file` that contains + `source code` that is not directly fed to a compiler. It is intended to be + used within other source files via the ``#include`` preprocessor directive. + + Header files usually use a special `file extension` that indicates their + being header files. Examples of header file extensions include ``.h`` and + ``.hpp`` + + public header root + + The subdirectory of the `library root` that contains the header files that + should be exposed to `library users `. + + .. seealso:: `Source Roots`_ + + private header root + + The subdirectory of the `library root` that contains the header files that + are required to compile the respective library, but *should not* be exposed + to the `library users `. + + It is possible that library does not have a private header root. + + .. seealso:: `Source Roots`_ + + compiled source root + + The subdirectory of the `library root` that contains the + `source files ` of the library that must be given to the + compiler to generate the library's translation units. + + It is possible that a library does not have a compiled source root. + + .. seealso:: + + - `Compiled Source Root`_ + - `Source Roots`_ + + public translation units + + The set of translation units generated for a library that are included when + linking downstream `library users `. + + .. seealso:: `Collecting the Public Translation Units`_ + + .. default-role:: math + + recognized compiled source file extension + + A :term:`file extension` that is defined to be a source file that generates + a translation unit containing the definition of entities for a library. + Comparing the file extension against the set of recognized extensions must + be a case-insensitive comparison. Only the lowercase extensions are listed + in this documentation. + + The source file extensions recognized by a tool will depend on the + programming language under scrutiny. + + Only the ``.c`` file extension is supported for the C programming language. + + The following file extensions are available for the C++ programming + language: + + - ``.cpp`` + - ``.cc`` + - ``.cxx`` + - ``.c++`` + + header search path + + A filepath from which a compiler will resolve references to header files. + + While the behavior of the ``#include`` directive is implementation-defined, + CRS (and |bpt|) assumes the following behavior: + + 1. When compiling a source file, the compiler has a list of + :term:`header search path`\ s `L` that it will use to resolve + ``#include`` directives. + 2. An ``#include`` or ``__has_include`` directive specifies a filepath `H` + of the form ``<``\ `H`\ ``>`` + 3. For each directory `L_s` in `L`: + + 1. Create a filepath `H_s` by joining `L_s` and `H` with a directory + separator. + 2. If `H_s` names a regular file, the directive will resolve to that + file. + + 4. If no directory in `L` was able to resolve `H`, the header is considered + to be not-found. + +.. default-role:: term + +Properties +########## + +The following are the salient attributes of a library within a package: + +- `library name` +- `library path` +- `library internal usages` +- `library external dependencies` + + +.. _crs.library.root: + +Roots +##### + +The `library root` is the directory in which the source files of a single +library reside. CRS recognizes two top-level subdirectories within a library +root: ``src/`` and ``include/``. A library root must contain one or both of +these directories. Each directory is a `source root`. CRS does not impose any +semantics on any other files in the library root. + +The following semantics apply, based on the presence of ``src/`` and/or +``include/``: + +- If **both** ``src/`` and ``include/`` are present in the library root, then + ``src/`` is the `private header root` and `compiled source root` for the + library, while ``include/`` is the `public header root`. +- Otherwise, if ``src/`` is present, then ``src/`` is the `public header root` + and the `compiled source root`. There is no `private header root`. +- Otherwise, ``include/`` must be present, and ``include/`` is the + `public header root`. There is no `private header root` nor is there a + `compiled source root`. + +One should note that a library can only have two distinct source root paths. It +is not possible that the `public header root`, `private header root`, and +`compiled source root` are all pointing to distinct locations. + + +Source Roots +************ + +A *source root* is a directory that contains library source files, including +header files. If the source root is a `compiled source root`, then that +directory may contain source files that will be used to generate the consumable +translation units for the library. If a source root is not *compiled*, then it +is a *header-only* source root. + +Both *compiled* and *header-only* source roots may contain headers, but whether +those headers can be resolved and used by downstream consumers depends on +whether the source root is the *public* header root or the *private* header +root. + + +Philosophy +========== + +A source root should have the following properties: + +- A source root is *relocatable*. No subdirectories are required to share this + property. +- A source root is a `header search path`. No subdirectories should be + `header search path`\ s. + +Being *relocatable* in this context means that the location of the directory on +the filesystem is irrelevant to the code contained within. As long as the files +within a source root are compiled with their `used-libraries ` +available, moving or renaming the source root directory should never result in +any ``#include`` directives failing to resolve. + +Code that explicitly assumes the location of its own source root, including in +relation to other source roots, is expressly unsupported by CRS. + + +.. rubric:: Example + +Suppose we have a library with the following source files (note the file paths): + +.. highlight:: cpp + +.. code-block:: + :caption: ``include/mylib/foo.hpp`` + + // I am a public header + +.. code-block:: + :caption: ``src/mylib/bar.hpp`` + + // I am a private header + +.. code-block:: + :caption: ``src/mylib/foo.cpp`` + + // [1] Okay: + #include + + // [2] Not okay + #include + + // [3] Not okay + #include "../include/foo.hpp" + + // [4] Okay and recommended + #include + + // [5] Okay and recommended + #include "./bar.hpp" + + // [6] Okay, but suspicious + #include "bar.hpp" + #include + + +This library has two `source root` directories: ``include/`` and ``src/``. +``src/`` is the `private header root` and `compiled source root`, while +``include/`` is the `public header root`. The following applies to each example: + +1. **Okay**: ```` is a fully-qualified path from the + `public header root` directory, which will be set as a `header search path` + while compiling the file. + +2. **Not okay**: The ```` directive will not resolve because that path + will not name an existing file when joined with the any `header search path`. + +3. **Not okay:** This will only work so long as the ``include/`` and ``src/`` + directories are siblings of the same parent directory, but this violates the + restriction that these directories be *relocatable*. + +4. **Okay and recommended**: Like ``[1]``, specifies a fully-qualified path from + the `private header root` directory, which will be added as a + `header search path` while compiling the file. + +5. **Okay**: Relative ``#include`` directives that specify a leading ``.`` or + ``..`` are unambiguous to the reader, although it is possible that they will + still resolve within a different `header search path` than the containing + file's own directory. + +6. **Okay, but suspicious**: While most compilers will insert the containing + directory of the file being compiled as a `header search path`, it is not + clear that the author is relying on this fact without the reader knowing that + ``bar.hpp`` names a file within the same directory. + + +Public Header Root +****************** + +The `public header root` is the `source root` directory that contains headers +that will be visible to the `library's users `. When compiling +the containing library and all of its users, the `public header root` of the +library should be added as a `header search path`. + +Transitive usage also applies: If library :math:`A` uses library :math:`B`, and +library :math:`B` uses library :math:`C`, the `public header root` of :math:`C` +should be included as a `header search path` while compiling :math:`A`, even if +:math:`A` does not have an explicit `library usage` on :math:`C`. + + +Private Header Root +******************* + +The `private header root` is the `source root` directory that contains headers +that should not be visible to the `library's users `, but *will* +be visible while compiling the library's `public translation units`. + +When compiling the `public translation units`, the `private header root` will be +added as a `header search path`. + +None of the header files in the library's `public header root` should refer to +the private headers. A verification step by compiling/checking the public +headers *should not* add the `private header root` as a `header search path`. + + +Compiled Source Root +******************** + +The `compiled source root` is the source root directory that contains the files +that will be used to generate the library's :term:`public translation units`. + + +Collecting the Public Translation Units +======================================= + +The `public translation units` of a |library| are given by finding the *public +compiled sources* of the library. + +For each file :math:`S` in the `compiled source root` `directory` and all descendent +directories, with a `filepath` :math:`F_s` as a `relative filepath` from its +containing source root: + +1. If the `file extension` of the `file stem` of :math:`F_s` is "``.test``" or + "``.main``", then :math:`S` *is not* a public compiled source. +2. Otherwise, if the `file extension` of :math:`F_s` is a + `recognized compiled source file extension`, then :math:`S` *is* a public + compile source. +3. Otherwise, :math:`S` *is not* a public compiled source. + +When linking a program :math:`P` that `uses ` a |library| +:math:`L`, every public translation unit of :math:`L` should be included in the +link operation. The linker *may* discard translation units which would be +unnecessary to generate :math:`P`. + + +Internal Usages +############### + +Libraries within a single `CRS package` + + +.. _crs.library.dependencies: + +External Dependencies +##################### + +Dependencies diff --git a/docs/crs/names.rst b/docs/crs/names.rst new file mode 100644 index 00000000..bb3158a1 --- /dev/null +++ b/docs/crs/names.rst @@ -0,0 +1,56 @@ +##### +Names +##### + +A CRS name can be validated by testing against the following regular +expression + +.. code-block:: text + + ^([a-z][a-z0-9]*)([._-][a-z0-9]+)*$ + +It checks the following rules: + +1. A name must begin with a lowercase ASCII alphabetic character (Must match + ``^[a-z]``). + +#. A name may not be an empty string. +#. A name may not contain any capital letter characters. +#. A name may only contain ASCII alphanumeric characters and the ASCII dot + "``.``", underscore ":literal:`_`", and hyphen "``-``". + +#. A name may not contain any adjacent punctuation characters. +#. A name must end with a letter or a digit. + +These name restrictions are currently in place to simplify path handling and +prevent havok from filepath normalization on certain filesystems. Future +revisions will likely loosen these requirements. + +Examples +######## + +.. |yes| replace:: ✔️ +.. |no| replace:: ❌ + +.. csv-table:: + :align: left + :widths: auto + + Name string, Is valid?, Reason + + .. default-role:: code + + `foo.bar`, |yes|, + `my-library.baz`, |yes|, + `foo_bar`, |yes|, + `somename`, |yes|, + `something-else`, |yes|, + `foo.`, |no|, Names may not end with a punctuation character + `Foo`, |no|, Names may not contain capital letters + `4g`, |no|, Names may not begin with a digit + `_mylibrary`, |no|, Names may not begin with underscores + `foo__bar`, |no|, Names may not contain adjacent punctuation or underscores + `foo..bar`, |no|, ‘‘ + `my-pkg.SomeLibrary`, |no|, Names may not contain capital letters. + +.. default-role:: any diff --git a/docs/crs/packages.rst b/docs/crs/packages.rst new file mode 100644 index 00000000..eb3479bf --- /dev/null +++ b/docs/crs/packages.rst @@ -0,0 +1,57 @@ +######## +Packages +######## + +.. |version| replace:: :hoverxreftooltip:`version ` + +.. |name| replace:: :doc:`name ` + +.. default-role:: term + +A CRS package is the unit of distribution in CRS. A package has a |name| and a +|version| and contains one or more `libraries `. + + +Encoded Attributes +################## + +A CRS package encodes the following high-level attributes: + +.. glossary:: + + package name + + The identity of the software that is being distributed in the package. + (Must be a valid |name|.) + + package version + + A version string for the package itself. At the time of writing, this is + required to be a :hoverxref:`Semantic Version String `. + Additional versioning formats may be considered in the future. + + package meta-version + + An integer constant that encodes the revision of the package itself, + regardless of the version of the source code inside. + + package libraries + + A list of libraries contained within the package. A single package may + contain any number of libraries. Libraries have further attributes, such as + :term:`library internal usages` and :term:`library external dependencies` + + .. seealso:: :doc:`libraries`. + + +Dependencies +############ + +Unlike most packaging formats, dependencies in `CRS` are not associated with +packages at the top-level. Instead, dependencies are associated with individual +libraries within a package. + +.. seealso:: + + - :ref:`Libraries\: External Dependencies ` + - :doc:`The documentation on dependencies and their attributes ` diff --git a/docs/crs/versions.rst b/docs/crs/versions.rst new file mode 100644 index 00000000..8a4cacd9 --- /dev/null +++ b/docs/crs/versions.rst @@ -0,0 +1,49 @@ +################## +Package Versioning +################## + +CRS Package versioning is based on `Semantic Versioning`_ + +.. _semver: + +Semantic Versioning +################### + +:title-reference:`Semantic Versioning` is a standard of software versioning that +defines a version string format and assigns semantics to each component of that +string. + +Examples of valid Semantic Version numbers: + +- ``1.2.3`` +- ``2.0.0`` +- ``2.0.5`` +- ``3.0.0-beta.1`` +- ``4.5.0-dev+2022.3.7`` + + +.. rubric:: Basic Syntax + +A basic Semantic Version string consists of three numeric values separated with +a dot "``.``":: + + X.Y.Z + +These numeric components are referred to as *major*, *minor*, and *patch*, +respectively:: + + .. + + +.. rubric:: Prereleases + +A Semantic Version string can also contain a *prerelease* suffix. A prerelease +suffix is attached to a base version number with a hyphen "``-``". The suffix is +an arbitrary sequence of alphanumeric identifiers separated by a dot "``.``":: + + ..- + + +.. seealso:: + + For more information on Semantic Versioning, refer to https://semver.org/ diff --git a/docs/guide/cli/build-deps.rst b/docs/guide/cli/build-deps.rst new file mode 100644 index 00000000..0af15f07 --- /dev/null +++ b/docs/guide/cli/build-deps.rst @@ -0,0 +1,24 @@ +``bpt build-deps`` +################## + +The ``bpt build-deps`` command is used to compile a set of dependencies for use +in another project. + +.. program:: bpt build-deps + +.. option:: ... + + One or more dependency strings. These match the ``dependencies`` strings + used in ``bpt.yaml``. + +.. include:: ./opt-toolchain.rst +.. include:: ./opt-tweaks-dir.rst +.. include:: ./opt-out.rst + +.. option:: --cmake + + Generate a CMake script that will create imported targets for the + dependencies that |bpt| builds. + +.. include:: ./opt-jobs.rst +.. include:: ./repo-common-args.rst diff --git a/docs/guide/cli/build.rst b/docs/guide/cli/build.rst new file mode 100644 index 00000000..96bb85dc --- /dev/null +++ b/docs/guide/cli/build.rst @@ -0,0 +1,30 @@ +``bpt build`` +############# + +``bpt build`` can be used to compile, link, and test a project or package. It +accepts the following options: + +.. program:: bpt build + +.. include:: ./opt-toolchain.rst +.. include:: ./opt-project.rst +.. include:: ./opt-out.rst + +.. option:: --no-tests + + Disabling compiling+linking of the project's tests. + + +.. option:: --no-apps + + Disable compiling+linking of the project's applications. + + +.. option:: --no-warn + + Disable compile/link warnings when building the project. Warning options are + specified as part of the :doc:`toolchain ` in use. + +.. include:: ./opt-tweaks-dir.rst +.. include:: ./opt-jobs.rst +.. include:: ./repo-common-args.rst diff --git a/docs/guide/cli/compile-file.rst b/docs/guide/cli/compile-file.rst new file mode 100644 index 00000000..8e0d5465 --- /dev/null +++ b/docs/guide/cli/compile-file.rst @@ -0,0 +1,25 @@ +``bpt compile-file`` +#################### + +``bpt compile-file`` can be used to compile individual source files in a project +or dependency. It accepts the following options: + +.. program:: bpt compile-file + +.. option:: ... + + Specify any number of source files that are compiled as part of the project. + |bpt| will compile these files. If any named files are not a part of the + project, |bpt| will fail with an error. + +.. include:: ./opt-toolchain.rst +.. include:: ./opt-project.rst + +.. option:: --no-warn + + Disable compiler warnings when compiling the given source files. + +.. include:: ./opt-out.rst +.. include:: ./opt-tweaks-dir.rst +.. include:: ./repo-common-args.rst + diff --git a/docs/guide/cli/index.rst b/docs/guide/cli/index.rst new file mode 100644 index 00000000..675d882d --- /dev/null +++ b/docs/guide/cli/index.rst @@ -0,0 +1,98 @@ +The |bpt| Command-Line Interface +################################ + +.. default-role:: term + +|bpt| ships as a single stand-alone executable. Brief help on any |bpt| +`command` can be accessed by passing the :option:`--help ` flag. + +These documentation pages will explain the `command-line interface` of the |bpt| +executable. + +.. seealso:: :doc:`terms` + +Base Options +************ + +The following `command-line arguments` are available for *all* |bpt| commands +and subcommands: + +.. program:: bpt + +.. option:: --help + + Access the "help" message from any subcommand. + +.. option:: --log-level {trace,debug,info,warn,error,critical,silent} + + Set the |bpt| logging level. ``trace`` will emit maximal warning + information, while ``silent`` will emit no information. All log output is + written to the ``stderr`` stream. + +.. option:: --crs-cache-dir + + Specify the directory used to store :term:`CRS` package metadata and + :term:`CRS package` files. + + .. seealso:: The :envvar:`BPT_CRS_CACHE_DIR` environment variable + + +Base Environment Variables +************************** + +The following `environment variables` can be used to control |bpt|'s behavior. +They each correspond to a common |bpt| `command-line arguments`. If |bpt| sees +both an environment variable definition and a given command-line argument, the +command-line argument will take precedence. + +.. envvar:: BPT_LOG_LEVEL + + An environment variable that controls :option:`--log-level`. + +.. envvar:: BPT_NO_DEFAULT_REPO + + Setting this environment variable to a "truthy" value will imply the + :option:`--no-default-repo ` flag to any |bpt| + command that accepts that flag. + +.. envvar:: BPT_CRS_CACHE_DIR + + An environment variable that sets the directory where |bpt| will store its + `CRS` metadata and cached `CRS packages `. + + This environment variable corresponds to the :option:`bpt --crs-cache-dir` + option. + +.. envvar:: BPT_JOBS + + Setting this environment variable to an integer value will specify the + default for the :option:`--jobs ` option. This can be used + to control the concurrency of |bpt| subprocesses that you may not have + access to directly change the `command` invocations. + +.. _cli.subcommands: + +|bpt| Subcommands +***************** + +|bpt| defines the following top-level subcommands: + +- :doc:`build` +- :doc:`compile-file` +- :doc:`build-deps` +- :doc:`pkg` +- :doc:`repo` +- :doc:`install-yourself` +- :doc:`new` + +.. toctree:: + :hidden: + + build + compile-file + build-deps + pkg + repo + install-yourself + new + terms diff --git a/docs/guide/cli/install-yourself.rst b/docs/guide/cli/install-yourself.rst new file mode 100644 index 00000000..7cbd504f --- /dev/null +++ b/docs/guide/cli/install-yourself.rst @@ -0,0 +1,34 @@ +``bpt install-yourself`` +######################## + +``bpt install-yourself`` is a utility subcommand used to install |bpt| on the +``PATH`` for execution from any command-line. Refer: +:ref:`tut.install.install-yourself`. + +.. program:: bpt install-yourself + +.. option:: --where {user,system} + + :default: ``user`` + + The intended scope of the installation. For ``system``, installs in a global + directory for all users of the system. For ``user``, installs in a + user-specific directory for executable binaries. + + User-local installation is highly recommended.d + +.. option:: --dry-run + + If specified, |bpt| will only write what *would* happen for the installation + without performing any action. + +.. option:: --no-modify-path + + If specified, |bpt| will not attempt to update any ``PATH`` environment + variables. + +.. option:: --symlink + + If specified, |bpt| will install a symoblic link to the |bpt| executable + that was used with ``install-yourself``, instead of copying the executable + to the destination. diff --git a/docs/guide/cli/new.rst b/docs/guide/cli/new.rst new file mode 100644 index 00000000..013a5fac --- /dev/null +++ b/docs/guide/cli/new.rst @@ -0,0 +1,20 @@ +``bpt new`` +########### + +``bpt new`` can be used to generate a |bpt| project. At time of writing, the +generated project is very simple. + +If no command-line arguments are provided, |bpt| will interactively ask for +values to be used to generate the project. + +.. program:: bpt new + +.. option:: + + The new name of the project. + +.. option:: --dir + + Specify the root directory of the new project. By default, will generate a + subdirectory of the working directory with the given + :option:`\` diff --git a/docs/guide/cli/opt-jobs.rst b/docs/guide/cli/opt-jobs.rst new file mode 100644 index 00000000..2b809f67 --- /dev/null +++ b/docs/guide/cli/opt-jobs.rst @@ -0,0 +1,7 @@ +.. option:: --jobs , -j + + Specify the maximum number of parallel tasks that |bpt| will allow to + execute in parallel. + + By default, will use the amount of hardware parallelism available on the + system, plus two. diff --git a/docs/guide/cli/opt-no-default-repo.rst b/docs/guide/cli/opt-no-default-repo.rst new file mode 100644 index 00000000..b3295b67 --- /dev/null +++ b/docs/guide/cli/opt-no-default-repo.rst @@ -0,0 +1,6 @@ +.. option:: --no-default-repo, -NDR + + Disable the default package repository for dependency/package lookup. + + This can also be enforced by setting the :envvar:`BPT_NO_DEFAULT_REPO` + environment variable to a "truthy" value. diff --git a/docs/guide/cli/opt-out.rst b/docs/guide/cli/opt-out.rst new file mode 100644 index 00000000..eb9076ba --- /dev/null +++ b/docs/guide/cli/opt-out.rst @@ -0,0 +1,6 @@ +.. |--out| replace:: + + Specify a :term:`filepath` to the directory where |bpt| will write its build + results and use as scratch space. By default, this will be the ``_build/`` + subdirectory of the working directory. + diff --git a/docs/guide/cli/opt-project.rst b/docs/guide/cli/opt-project.rst new file mode 100644 index 00000000..bc55ebd8 --- /dev/null +++ b/docs/guide/cli/opt-project.rst @@ -0,0 +1,5 @@ +.. option:: --project , -p + + Specify the :term:`filepath` to a :term:`directory` containing a |bpt| + project. If not specified, the project in the :term:`working directory` will + be used. diff --git a/docs/guide/cli/opt-repo-sync.rst b/docs/guide/cli/opt-repo-sync.rst new file mode 100644 index 00000000..2f45d546 --- /dev/null +++ b/docs/guide/cli/opt-repo-sync.rst @@ -0,0 +1,26 @@ +.. option:: --repo-sync {always,cached-okay,never} + + Mode for repository metadata synchronization. Default is ``always``. + + ``always`` + Always try to keep the repository metadata up-to-date. If there is a + failure to validate/update the repo metadata, the build fails + immediately. + + ``cached-okay`` + Attempt to update the repository metadata. If a low-level network error + prevents such an update and we have cached metadata for the repository, + ignore the error and continue. + + ``never`` + Do not try to update the repository metadata. This option requires that + there be a local cache of the repository metadata before being used. + + If any packages need to be pulled for the build and those packages are + not already locally cached, |bpt| will still attempt to download those + packages from the repository. + + Regardless of this option, the HTTP ``Cache-Control`` headers for the + repository data will be respected. If repository data is within the lifetime + of the ``max-age`` of the resource, |bpt| will not try to update the + repository data. diff --git a/docs/guide/cli/opt-toolchain.rst b/docs/guide/cli/opt-toolchain.rst new file mode 100644 index 00000000..d195307b --- /dev/null +++ b/docs/guide/cli/opt-toolchain.rst @@ -0,0 +1,6 @@ +.. option:: --toolchain , -t + + Specify the :doc:`toolchain ` to use. Can be a + :term:`filepath` to a :ref:`toolchain file ` or the name of + a :ref:`built-in toolchain `. If not provided, |bpt| + will try to load a :ref:`default toolchain `. diff --git a/docs/guide/cli/opt-tweaks-dir.rst b/docs/guide/cli/opt-tweaks-dir.rst new file mode 100644 index 00000000..935ef58d --- /dev/null +++ b/docs/guide/cli/opt-tweaks-dir.rst @@ -0,0 +1,4 @@ +.. option:: --tweaks-dir , -TD + + Specify the :term:`filepath` to a :term:`directory` containing + :term:`tweak-headers` to be used for the build. diff --git a/docs/guide/cli/opt-use-repo.rst b/docs/guide/cli/opt-use-repo.rst new file mode 100644 index 00000000..e3054dfe --- /dev/null +++ b/docs/guide/cli/opt-use-repo.rst @@ -0,0 +1,8 @@ +.. option:: --use-repo , -r + + Specify the :term:`URL` or :term:`filepath` to a package repository to use + for package/dependency lookup. This option can be repeated for multiple + repositories. The default repository will always be available unless + :option:`--no-default-repo` is specified. + + Only packages in any expressly-enabled repositories will be available. diff --git a/docs/guide/cli/pkg.rst b/docs/guide/cli/pkg.rst new file mode 100644 index 00000000..0f1509c6 --- /dev/null +++ b/docs/guide/cli/pkg.rst @@ -0,0 +1,85 @@ +``bpt pkg`` +########### + +``bpt pkg`` is a family of subcommands that can be used to create and inspect +packages. + +.. _cli.pkg-search: + +``bpt pkg search`` +****************** + +``bpt pkg search`` will search for packages available in one or more +repositories. + +.. program:: bpt pkg search + +.. option:: + + A name or glob-style pattern to search for. Matching packages will be listed + in the command output. Searching is case-insensitive. Only the name of the + package will be matched (not the version). If omitted, all packages will be + listed. + +.. include:: ./repo-common-args.rst + + +``bpt pkg create`` +****************** + +``bpt pkg create`` will generate a :term:`CRS package` from a |bpt| project. + +.. program:: bpt pkg create + +.. include:: ./opt-project.rst + +.. option:: --out , -o + + Specify the :term:`filepath` at which the :term:`CRS package` archive file + will be written. The default is a filename based on the name and version of + the input package. + +.. option:: --if-exists {replace,ignore,fail} + + Specify the behavior of |bpt| in case the output package file already + exists. The default value is ``fail``. + + +``bpt pkg prefetch`` +******************** + +``bpt pkg prefetch`` can be used to fetch packages and package metadata from +remotes so that it will be immediately available in subsequent operations. + +.. note:: + + This only pulls packages into the :term:`CRS` package cache (specified by + :option:`bpt --crs-cache-dir`). It can be used to pre-seed the package cache + before subsequent operations need to pull those packages. + +.. program:: bpt pkg prefetch + +.. option:: ... + + Any number of package IDs to fetch from repositories. Package IDs are of the + form ``{name}@{version}``. + +.. include:: ./repo-common-args.rst + + +``bpt pkg solve`` +***************** + +``bpt pkg solve`` will attempt to generate a dependency solution from the given +dependency strings specified on the command line. + +The requirements will be printed as the output to the |bpt| command. + +.. program:: bpt pkg solve + +.. option:: ... + + One or more dependency statements for which |bpt| will to try and generate a + solution. + +.. include:: ./repo-common-args.rst diff --git a/docs/guide/cli/repo-common-args.rst b/docs/guide/cli/repo-common-args.rst new file mode 100644 index 00000000..0d2419d5 --- /dev/null +++ b/docs/guide/cli/repo-common-args.rst @@ -0,0 +1,3 @@ +.. include:: ./opt-use-repo.rst +.. include:: ./opt-no-default-repo.rst +.. include:: ./opt-repo-sync.rst diff --git a/docs/guide/cli/repo.rst b/docs/guide/cli/repo.rst new file mode 100644 index 00000000..638d4e9f --- /dev/null +++ b/docs/guide/cli/repo.rst @@ -0,0 +1,146 @@ +``bpt repo`` +############ + +.. default-role:: term + +``bpt repo`` is used to create and manage repository directories. + +.. note:: + + This command is used to manage the repositories upstream, and is not + relevant to managing the repositories used on the client-side. + + During builds, |bpt| uses options such as :option:`bpt build --use-repo` to + control repositories used for a build. + + +.. _cli.repo-init: + +``bpt repo init`` +***************** + +``bpt repo init `` will initialize a new `CRS` repository in the given +directory + +.. program:: bpt repo init + +.. option:: + + The `filepath` to a `directory` in which to initialize a new repository. + +.. option:: --name + + :required: Specify the name of the new repostiory. This can be any free-form + string. It is recommended to use the domain name (and possible URL path) + at which the repository is intended to be accessed. This string is not + usually seen in the |bpt| user interface. + + .. important:: + + It is essential that the name of the repository be *globally* unique, as it + is used as the cache key in |bpt| when storing package metadata. + +.. option:: --if-exists {replace,ignore,fail} + + The action to perform if there is already a repository present in the given + :option:`\`. + + ``fail`` (The default) + Report an error and exit non-zero. + + ``ignore`` + Do no action. Reports a notice and exits zero. + + ``replace`` + Delete the existing repository database and create a new one in its place. + + +``bpt repo import`` +******************* + +``bpt repo import `` will import one or more `CRS package` archive +files into a repository at the given directory. + +.. program:: bpt repo import + +.. option:: + + .. |repo-dir-arg| replace:: + + The repository directory to managed. Must have been initialized using + :ref:`cli.repo-init`. + + |repo-dir-arg| + +.. option:: ... + + The `filepath` to one or more `CRS packages ` or |bpt| projects + to import. + + If the given path points to a |bpt| project, a CRS package archive will be + generated on-the-fly for the project. + + Any number of package paths may be provided. + +.. option:: --if-exists {replace,ignore,fail} + + The action to perform if any of the given :option:`\` paths + identify packages which are already present in the repository at + :option:`\`. + + ``fail`` (The default) + Report an error and exit non-zero. + + ``ignore`` + Skip the already-present package. + + ``replace`` + Delete the existing package entry and create a new one in its place. + + +``bpt repo remove`` +******************* + +``bpt repo remove `` will remove packages from a repostiory. + +.. program:: bpt repo remove + +.. option:: + + |repo-dir-arg| + +.. option:: ... + + The ``{name}@{version}~{revision}`` identifiers of packages to remove. Can be + provided multiple times. + + +``bpt pkg ls`` +************** + +``bpt pkg ls `` will print a list of the packages in a repository. +Each package will be of the form ``{name}@{version}~{revision}``, one package ID +per line. + +.. program:: bpt repo ls + +.. option:: + + |repo-dir-arg| + + +``bpt repo validate`` +********************* + +``bpt repo validate `` validates that every package individually can +be installed using only other packages in the same repository. + +For every package in the repository, |bpt| will attempt to form a valid +dependency solution thereof, using only packages in that same repo as dependency +candidates + +.. program:: bpt repo validate + +.. option:: + + |repo-dir-arg| diff --git a/docs/guide/cli/terms.rst b/docs/guide/cli/terms.rst new file mode 100644 index 00000000..461a2163 --- /dev/null +++ b/docs/guide/cli/terms.rst @@ -0,0 +1,28 @@ +######################## +Command-Line Terminology +######################## + +This page lists common terminology used by |bpt| and this documentation for +command-line interfaces. + +.. default-role:: term + +.. glossary:: + + command + + A *command* is a series of words (including punctuation) given to run a + program with some set of `command-line arguments`. + + A command may be typed at `command-line interface` or be executed + automatically by a process. + + command-line interface + + A user interface to an application that operates using only plaintext typed + into a command interpreter and written back to the user as text output. + + command-line arguments + + The series of words and punctuation given to a `command` that control the + behavior of the program. diff --git a/docs/guide/filesystem.rst b/docs/guide/filesystem.rst new file mode 100644 index 00000000..8c3f5640 --- /dev/null +++ b/docs/guide/filesystem.rst @@ -0,0 +1,181 @@ +###################### +Filesystem Terminology +###################### + +This page lists various terminology used by |bpt| and :doc:`CRS ` +for filesystem paths and manipulation. + + +.. default-role:: term + +.. glossary:: + + directory + + A directory is a filesystem object that can contain other files and + directories. These are sometimes called "folders," as it is common to be + represented with a folder icon. + + subdirectory + + The term "subdirectory" simply refers to a `directory` that is the child of + another `directory`. + + working directory + + Every process on an operating system has a single "working directory" + `filepath`. This is usually inherited from the parent process that started + the child process. + + In a command-line environment, the working directory can be controlled with + the ``cd`` command. + + path + filepath + + A filepath (sometimes just "path") is a text string that represents a + location on the filesystem. A filepath may be a `relative filepath` or an + `absolute filepath`. + + absolute filepath + + An *absolute* filepath is a `filepath` that identifies a unique and + unambiguous location on a filesystem. Any filepath that is not an *absolute* + filepath is a `relative filepath`. + + On Unix-like systems, a filepath that begins with a `directory separator` is + an absolute filepath, e.g. ``/foo/bar`` is *absolute*, while ``foo/bar`` is + *relative*. + + On Windows, an absolute path requires a *root name* (e.g. a drive letter) + followed by a `directory separator`. A path such as ``/foo/bar`` is + *drive-relative* on Windows. One can resolve a drive-relative path to an + absolute path by prepending a drive letter, such as ``C:`` in + ``C:/foo/bar``. Windows applications will often accept ``/foo/bar`` in place + of absolute path, since it is often unambiguous with context what the path + identifies. + + relative filepath + + A *relative* filepath is a `filepath` that identifies a filesystem location + "relative" to some other filepath. Any filepath that is not an + `absolute filepath` is a relative filepath. + + "Resolving" a relative filepath is done by concatenating some base path with + the relative filepath, joined by a `directory separator`. + + For example, given a relative path ``foo/bar`` and a Unix-like base absolute + path ``/some/directory``, the relative path can be resolved by appending a + `directory separator` to the base path followed by the relative path, + resulting in the new absolute path ``/some/directory/foo/bar``. + + directory separator + + A character used within a `filepath` to delineate the components of that + path. + + In a filepath such as ``foo/bar``, "``foo``" would be a directory that + contains a file named ``bar``. The "``/``" represents the "parent path of" + relationship. + + On Unix-like systems, the directory separator is a forward-slash "``/``". On + Windows, both the forward-slash *and* the back-slash "``\``" are valid as + directory separators. + + Multiple adjacent directory separators in a `filepath` are equivalent to a + single directory separator. e.g. ``foo//bar////baz.txt`` identifies the same + location as ``foo/bar/baz.txt``. + + filename + + A *filename* is the right-most component of a `filepath`, with any parent + directory path removed. Any filename can also be considered a + `relative filepath` with a single path component. + + .. default-role:: math + + Given a :term:`filepath` string `P`, the *filename* of `P` is the substring + of `P` beginning immediately after the final :term:`directory separator` + until the ened of the string, with the following points to consider: + + - If `P` is an empty string, the filename is an ASCII dot "``.``" + - If `P` ends with a :term:`directory separator`, the filename is an ASCII + dot "``.``" + - If `P` does not contain a directory separator, the entire string `P` is + the filename itself. + + file extension + + The *file extension* of a :term:`filepath` is the substring of it's + :term:`filename` beginning at the final ASCII dot "``.``" until the end of + the string, unless the first character of the :term:`filename` is the final + ASCII dot "``.``". + + .. csv-table:: Examples + :align: center + :widths: auto + + .. default-role:: literal + + :term:`Filepath`, File extension, Explanation + `baz.txt`, `.txt`, + `bar.txt.gz`, `.gz`, Only the right-most extension is considered. + `foo/bar.tar.gz`, `.gz`, The parent directory path is irrelevant. + `foo.dir/bar.tgz`, `.tgz`, The parent directory path is irrelevant. + `some_file`, (empty string), There is no dot in the :term:`filename` + `foo.dir/some_file`, (empty string), There is no dot in the :term:`filename` + `file`, (Empty string) + `foo/bar/.`, (Empty string) + `foo/bar/..`, (Empty string) + `.hidden.txt`, `.txt` + `.hidden`, (Empty string), The initial dot is not part of the extension + + .. default-role:: math + + .. rubric:: File extension algorithm + + Given a filepath `P`, with the :term:`filename` of `P` as `F`, then the file + extension `E` of `P` is calculated as: + + 1. If `F` begins with an ASCII dot "``.``", remove it. + 2. If `F` is a single ASCII ddot "``.``", then `E` is an empty string. + 3. Otherwise, if `F` does not contain an ASCII dot "``.``", `E` is an empty + string. + 4. Otherwise, `E` is the substring of `F` beginning at (and including) the + last ASCII dot "``.``" in `F` until the end of `F` + + file stem + + The *file stem* of a filepath `P` is the :term:`filename` of `P` with the + :term:`file extension` removed. + + .. note:: + + When obtaining the file stem of a string, only the outer-most + :term:`file extension` should be removed. + + .. csv-table:: + :align: center + :widths: auto + + .. default-role:: literal + :term:`Filepath`, File stem, Explanation + `baz.txt`, `baz`, Removed `.txt` + `/foo/bar/baz.txt`, `baz`, Removed the parent directory path and `.txt` + `file.tar.gz`, `file.tar`, Only the final `.gz` is removed. + `file`, `file`, "No extension, so the :term:`filename` is the file stem" + `foo/bar`, `bar`, "No extension, so the :term:`filename` is the file stem" + `foo/bar/.`, `.`, + `foo/bar/..`, `..` + `foo/bar/`, `.`, The :term:`filename` is "`.`" + `.hidden.txt`, `.hidden`, + + parent filepath + + .. default-role:: term + + The *parent* filepath of some `filepath` :math:`P` is the substring of + :math:`P` that identifies the directory that would contain the file + identified by :math:`P`. If :math:`P` is only a `filename`, the parent + filepath is the single ASCII dot "``.``" to refer to the + `working directory`. diff --git a/docs/guide/index.rst b/docs/guide/index.rst index bb915f4f..1620131b 100644 --- a/docs/guide/index.rst +++ b/docs/guide/index.rst @@ -1,11 +1,10 @@ -.. _guide: - User Guide ########## .. toctree:: :maxdepth: 2 + cli/index packages toolchains source-dists @@ -14,3 +13,13 @@ User Guide interdeps build-deps cmake + + +Terminology Guides +****************** + +.. toctree:: + :maxdepth: 2 + + filesystem + terms diff --git a/docs/guide/terms.rst b/docs/guide/terms.rst new file mode 100644 index 00000000..616b5d92 --- /dev/null +++ b/docs/guide/terms.rst @@ -0,0 +1,106 @@ +######################### +Miscellaneous Terminology +######################### + +.. default-role:: term + +This page documents miscellaneous terminology used throughout |bpt| and `CRS`. + +.. glossary:: + + JSON + + JSON is the *JavaScript Object Notation*, a plaintext format for + representing semi-structured data. + + JSON values can be strings, numbers, boolean values, a ``null`` value, + arrays of values, and "objects" which map a string to another JSON value. + + .. rubric:: Example + + .. code-block:: json + :caption: ``example.json`` + + { + "foo": 123.0, + "bar": [true, false, null], + "baz": "quux", + "another": { + "nested-object": [], + } + } + + JSON data cannot contain comments. The order of keys within a JSON object is + not significant. + + + YAML + + YAML is a data representation format intended to be written by humans and + contain arbitrarily nested data structures. + + YAML is a superset of `JSON`, so every valid JSON document is also a valid + equivalent YAML document. + + You can learn more about YAML at https://yaml.org. + + The example from the `JSON` definition could also be written in YAML as: + + .. code-block:: yaml + :caption: ``example.yaml`` + + foo: 123.0 + bar: + - true + - false + - null + # We can use comments in YAML! + baz: quux + another: + nested-object: [] + + YAML can also be written as a "better JSON" by using the data block + delimiters: + + .. code-block:: yaml + :caption: ``example.yaml`` + + { + foo: 123.0, + bar: [true, false, null], + # We can still use comments! + baz: "quux", + another: {nested-object: []}, # Trailing commas are allowed! + } + + tweak-headers + + Special `header files
` that are used to inject configuration + options into dependency libraries. The library to be configured must be + written to support tweak-headers. + + Tweak headers are placed in the "tweaks directory", which is controlled with + the :option:`bpt build --tweaks-dir <--tweaks-dir>` option given to |bpt| + build commands. + + .. seealso:: For more information, `refer to this article`__. + + __ https://vector-of-bool.github.io/2020/10/04/lib-configuration.html + + URL + + A **U**\ niform **R**\ esource **L**\ ocator is a string that specifies how to + find a resource, either on the network/internet or on the local filesystem. + + environment variables + + Every operating system process has a set of *environment variables*, which + is an array of key-value pairs that map a text string key to some text + string value. These are commonly used to control the behavior of commands + and subprocesses. + + For example, the "``PATH``" environment variable controls how `command` + names are mapped to executable files. + + |bpt| uses some environment variables to control some behavior, such as + :envvar:`BPT_LOG_LEVEL` and :envvar:`BPT_NO_DEFAULT_REPO`. diff --git a/docs/guide/toolchains.rst b/docs/guide/toolchains.rst index 36cd72f7..01a5e5bb 100644 --- a/docs/guide/toolchains.rst +++ b/docs/guide/toolchains.rst @@ -26,6 +26,7 @@ effectively in your project. appropriate environment in order for the Visual C++ toolchain executables and files to be available. +.. _toolchains.file: Passing a Toolchain ******************* diff --git a/docs/howto/cmake.rst b/docs/howto/cmake.rst index f881bf39..83b84dd5 100644 --- a/docs/howto/cmake.rst +++ b/docs/howto/cmake.rst @@ -49,7 +49,7 @@ Including PMM ============= Suppose I have downloaded and committed `pmm.cmake`_ into the ``tools/`` -subdirectory of my CMake project. To use it in CMake, I first need to +`subdirectory` of my CMake project. To use it in CMake, I first need to ``include()`` the script. The simplest way is to simply ``include()`` the file .. code-block:: @@ -61,9 +61,9 @@ subdirectory of my CMake project. To use it in CMake, I first need to include(tools/pmm.cmake) -The ``include()`` command should specify the path to ``pmm.cmake``, including -the file extension, relative to the directory that contains the CMake script -that contains the ``include()`` command. +The ``include()`` command should specify the `relative path` to ``pmm.cmake``, +including the `file extension`, relative to the `directory` that contains the +CMake script that contains the ``include()`` command. Running PMM @@ -85,7 +85,7 @@ The basic signature of the ``pmm(BPT)`` command looks like this:: The most straightforward usage is to use only the ``DEPENDS`` argument. For example, if we want to import `{fmt} `_:: - pmm(BPT DEPENDS "fmt^7.0.3") + pmm(BPT DEPENDS "fmt@7.0.3") When CMake executes the ``pmm(BPT ...)`` line above, PMM will download the appropriate |bpt| executable for your platform, generate @@ -115,11 +115,10 @@ Like with |bpt|, CMake wants us to explicitly declare how our build targets *use* other libraries. After ``pmm(BPT)`` executes, there will be ``IMPORTED`` targets that can be linked against. -In |bpt| (and in libman), a library is identified by a combination of -*namespace* and *name*, joined together with a slash ``/`` character. This -*qualified name* of a library is decided by the original package author or -maintainer, and should be documented. In the case of ``fmt``, the only library -is ``fmt/fmt``. +In |bpt| a library is identified by a combination of *package name* and *library +name*, joined together with a slash ``/`` character. This *qualified name* of a +library is decided by the original package author or maintainer, and should be +documented. In the case of ``fmt``, the only library is ``fmt/fmt``. When ``pmm(BPT)`` imports a library, it creates a qualified name using a double-colon "``::``" instead of a slash. As such, our ``fmt/fmt`` is imported @@ -141,7 +140,7 @@ In all, this is our final ``CMakeLists.txt``: project(MYApplication VERSION 2.1.3) include(tools/pmm.cmake) - pmm(BPT DEPENDS fmt^7.0.3) + pmm(BPT DEPENDS fmt@7.0.3) add_executable(my-application app.cpp) target_link_libraries(my-application PRIVATE fmt::fmt) @@ -154,7 +153,7 @@ Changing Compile Options :doc:`toolchains `. PMM supports specifying a toolchain using the ``TOOLCHAIN`` argument:: - pmm(BPT DEPENDS fmt^7.0.3 TOOLCHAIN my-toolchain.json5) + pmm(BPT DEPENDS fmt@7.0.3 TOOLCHAIN my-toolchain.json5) Of course, writing a separate toolchain file just for your dependencies can be tedious. For this reason, PMM will write a toolchain file on-the-fly when it diff --git a/docs/howto/deps.rst b/docs/howto/deps.rst index a76c3d04..3dbfca10 100644 --- a/docs/howto/deps.rst +++ b/docs/howto/deps.rst @@ -5,10 +5,11 @@ Of course, fundamental to any build system is the question of consuming dependencies. |bpt| takes an approach that is both familiar and novel. The *Familiar*: - Dependencies are listed in a project's package manifest file - (``package.json5``, for |bpt|). - A range of acceptable versions is provided in the package manifest, which + Dependencies are listed in a project's manifest file (``bpt.yaml``, for + |bpt|). + + A range of acceptable versions is provided in the project manifest, which tells |bpt| and your consumers what versions of a particular dependency are allowed to be used with your package. @@ -16,10 +17,12 @@ The *Familiar*: listed in the manifest as well. The *Novel*: - |bpt| does not have a separate "install" step. Instead, whenever a ``bpt - build`` is executed, the dependencies are resolved, downloaded, extracted, - and compiled. Of course, |bpt| caches every step of this process, so you'll - only see the download, extract, and compilation when you add a new dependency, + + |bpt| does not have a separate "install" step. Instead, whenever a + ``bpt build`` is executed, the dependencies are resolved, downloaded, + extracted, and compiled. Of course, |bpt| caches every step of this process, + so you'll only see the download, extract, and compilation when you add a new + dependency, Additionally, changes in the toolchain will necessitate that all the dependencies be re-compiled. Since the compilation of dependencies happens @@ -35,82 +38,51 @@ Listing Package Dependencies Suppose you have a project and you wish to use `spdlog `_ for your logging. To begin, we need -to find a ``spdlog`` package. We can search via ``bpt pkg search``:: +to find a ``spdlog`` package. We can search via :ref:`cli.pkg-search`:: $ bpt pkg search spdlog Name: spdlog - Versions: 1.4.0, 1.4.1, 1.4.2, 1.5.0, 1.6.0, 1.6.1, 1.7.0 - From: repo-1.dds.pizza - No description - -.. note:: - If you do not see any results, you may need to add the main repository to - your package database. Refer to :doc:`/guide/remote-pkgs`. + Versions: 1.4.0, 1.4.1, 1.4.2, 1.5.0, 1.6.0, 1.6.1, 1.7.0, 1.8.0, 1.8.1, + 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.9.0, 1.9.1, 1.9.2 + From: https://repo-2.dds.pizza/ In the output above, we can see one ``spdlog`` group with several available -versions. Let's pick the newest available, ``1.7.0``. +versions. Let's pick the newest available, ``1.9.2``. If you've followed at least the :doc:`Hello, World tutorial `, -you should have at least a ``package.json5`` file present. Dependencies are -listed in the ``package.json5`` file under the ``depends`` key as an array of -dependency statement strings: - -.. code-block:: js - :emphasize-lines: 5-7 - - { - name: 'my-application', - version: '1.2.3', - namespace: 'myself', - depends: [ - "spdlog^1.7.0" - ] - } - -The string ``"spdlog^1.7.0"`` is a *dependency statement*, and says that we want -``spdlog``, with minimum version ``1.7.0``, but less than version ``2.0.0``. -Refer to :ref:`deps.ranges` for information on the version range syntax. +you should have at least a ``bpt.yaml`` file present. Dependencies are listed in +the ``bpt.yaml`` file under the ``dependencies`` key as a list of dependency +statement strings: -This is enough that |bpt| knows about our dependency, but there is another -step that we need to take: +.. code-block:: yaml + :caption: ``bpt.yaml`` + :emphasize-lines: 3,4 + name: my-application + version: 1.2.3 + dependencies: + - spdlog@1.9.2 using spdlog -Listing Usage Requirements -************************** - -The ``depends`` is a package-level dependency, but we need to tell |bpt| that -we want to *use* a library from that package. For this, we need to provide a -``library.json5`` file alongside the ``package.json5`` file. - -.. seealso:: - The ``library.json5`` file is discussed in :ref:`pkgs.libs` and - :ref:`deps.lib-deps`. - -We use the aptly-named ``uses`` key in ``library.json5`` to specify what -libraries we wish to use from our package dependencies. In this case, the -library from ``spdlog`` is named ``spdlog/spdlog``: - -.. code-block:: js +The string ``"spdlog@1.9.2"`` is a *dependency statement*, and says that we want +``spdlog``, with minimum version ``1.9.2``, but less than version ``2.0.0``. +Refer to :ref:`deps.ranges` for information on the version range syntax. - { - name: 'my-application', - uses: [ - 'spdlog/spdlog' - ] - } +The ``using spdlog`` suffix declares that we want to use the ``spdlog`` +libraries within the package. This will attach the ``spdlog/spdlog`` library to +the libraries within our own project. Using Dependencies ****************** -We've prepared our ``package.json5`` and our ``library.json5``, so how do we get -the dependencies and use them in our application? +We've prepared our ``bpt.yaml`` so how do we get the dependencies and use them +in our code? Simply *use them*. There is no separate "install" step. Write your application as normal: .. code-block:: cpp - :caption: src/app.main.cpp + :caption: ``src/app.main.cpp`` #include @@ -118,7 +90,7 @@ as normal: spdlog::info("Hello, dependency!"); } -Now, when you run ``bpt build``, you'll see |bpt| automatically download +Now when you run ``bpt build``, you'll see |bpt| automatically download ``spdlog`` *as well as* ``fmt`` (a dependency of ``spdlog``), and then build all three components *simultaneously*. The result will be an ``app`` executable that uses ``spdlog``. diff --git a/docs/index.rst b/docs/index.rst index 62ae6b3b..20abc6b3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,3 +1,4 @@ +##### |bpt| ##### @@ -12,6 +13,10 @@ projects. If you're completely new and have no idea what the project is about, check out the :doc:`tut/index` page. + +Table of Contents +################# + .. toctree:: :maxdepth: 2 @@ -21,3 +26,7 @@ the :doc:`tut/index` page. design dev/index err/index + crs/index + +- :ref:`Index of Terms ` +- :ref:`Search ` diff --git a/docs/static/styles.css b/docs/static/styles.css new file mode 100644 index 00000000..bfcba03e --- /dev/null +++ b/docs/static/styles.css @@ -0,0 +1,24 @@ +code.bpt-name.literal > span.pre { + font-weight: bold; +} + +p > code.bpt-name.literal > span.pre { + font-size: 14pt; +} + +code.literal:not(.bpt-name) { + border: 1px solid #0004; + padding: 1px 4px; + border-radius: 4px; + background-color: #0001; + white-space: nowrap; +} + +pre span.linenos { + border-right: 2px solid green; + margin-right: 8px; +} + +a.hoverxref.tooltip { + white-space: nowrap; +} \ No newline at end of file diff --git a/docs/tut/hello-test.rst b/docs/tut/hello-test.rst index 19997fad..cae47c54 100644 --- a/docs/tut/hello-test.rst +++ b/docs/tut/hello-test.rst @@ -1,20 +1,21 @@ A *Hello, World* Test ##################### +.. default-role:: term + So far, we have a simple library with a single function: ``get_greeting()`` and an application that makes use of it. How can we test it? -With |bpt|, similar to generating applications, creating a test requires -adding a suffix to a source filename stem. Instead of ``.main``, simply add -``.test`` before the file extension. +With |bpt|, similar to generating applications, creating a test requires adding +a suffix to a source `filename stem `. Instead of ``.main``, simply +add ``.test`` before the `file extension`. A New Test Executable ********************* We'll create a test for our ``strings`` component, in a file named -``strings.test.cpp``. We'll use an ``assert`` to check our ``get_greeting()`` -function: +``strings.test.cpp``. .. code-block:: c++ :caption: ``/src/hello/strings.test.cpp`` @@ -26,6 +27,7 @@ function: if (hello::get_greeting() != "Hello world!") { return 1; } + return 0; } If you run ``bpt build`` once again, |bpt| will generate a test executable and @@ -57,28 +59,32 @@ than being a strong dependency of the library itself. A "for test" library dependency will only be available within the ``.test.*`` source files, and downstream library consumers will not see the dependency. -To declare dependencies, we return to the ``bpy.yaml`` file. We'll declare a +To declare dependencies, we return to the ``bpt.yaml`` file. We'll declare a dependency on the `Catch2`_ C and C++ unit testing framework: .. _Catch2: https://github.com/catchorg/Catch2 .. code-block:: yaml - :caption: ``/bpy.yaml`` + :caption: ``/bpt.yaml`` :emphasize-lines: 3,4 name: hello-bpt version: 0.1.0 - dependencies: - - catch2@2.13.7 using main for test + test-dependencies: + - catch2@2.13.7 using main The dependency declaration here is using a special shorthand string to declare how we wish to consume the dependency. The shorthand string here says that we depend on "``catch2``" version ``2.13.7`` (or any compatible version), and we -are "using" a library from the package called "``main``" for "``test``" only. +are "using" a library from the package called "``main``". This library in Catch2 +defines a ``main()`` function on our behalf that will run all the tests defined +in our test `source file`. Adding the dependency under the ``test-dependencies`` +key means that the dependency is only loaded for testing purposes and doesn't +propagate to our own users. If you now run ``bpt build``, we will likely get a linker error for a -multiply-defined ``main`` function. The ``catch2::main`` library contains its -own definition of the ``main()`` function. This means we cannot provide our own +multiply-defined ``main`` function. The ``catch2/main`` library contains its own +definition of the ``main()`` function. This means we cannot provide our own ``main`` function, and should instead use Catch's ``TEST_CASE`` macro to declare our test cases. @@ -89,7 +95,6 @@ same, though: .. code-block:: c++ :caption: ``/src/hello/strings.test.cpp`` - :linenos: :emphasize-lines: 3, 5-7 #include diff --git a/docs/tut/hello-world.rst b/docs/tut/hello-world.rst index a80aea0a..b52a7206 100644 --- a/docs/tut/hello-world.rst +++ b/docs/tut/hello-world.rst @@ -1,59 +1,75 @@ A *Hello, world!* Application ############################# +.. default-role:: term + Creating a *hello world* application is very simple. +Creating a New Project +********************** + +Creating a very basic project can be done with the ``bpt new`` `command`: -Creating a *Package Root* -************************* +.. code-block:: bash -To start, create a new directory for your project. This will be known as the -*package root*, and the entirety of our project will be placed in this -directory. The name and location of this directory is not important, but the -contents therein will be significant. + $ bpt new hello-bpt -.. note:: +|bpt| will ask you a few questions to begin. Accept the defaults for now. This +will create a new project named "``hello-bpt``" in a new `directory` also named +"``hello-bpt/``". (By default, ``bpt new`` will create the project in a +`subdirectory` with the same name as the project itself.) - The term *package root* is further described in the :doc:`/guide/packages` - page. +.. seealso:: The subcommand documentation: :doc:`/guide/cli/new` -From here on, this created directory will simply be noted as ````. In the -examples, this will refer to the package root directory we have created. +From here on, the `directory` of the ``hello-bpt/`` created by this `command` +will simply be referred to as ````. -Creating the First *Source Root* -******************************** +The New Project Files +********************* -Within the package root, we create our first *source root*. Since we are -intending to compile files, we need to use the name that |bpt| has designated -to be the source root that may contain compilable source files: ``src/``: +Within the new project `directory`, ``bpt`` will create a ``bpt.yaml`` and a +``src/`` directory. (If you chose to split headers and sources, it will also +create an ``include/`` directory.) -.. code-block:: bash +The ``bpt.yaml`` declares the information about the project that |bpt| will use +to build, package, test, and distribute the project. + +The ``src/`` (and possible ``include/``) `subdirectories ` are +used to contain the `source code` of the project. |bpt| will search for and +compile `source files ` that you add to these directories, +including any nested subdirectories of those top-level directories. The ``src/`` +and ``include/`` directories are referred to as `source roots `. - mkdir src +The default project created by ``bpt new`` will contain a single source file and +a single header file. If you accepted the defaults of ``bpt new hello-bpt``, +these will be: -You should now have a single item in the package root, at ``/src/``. This -is the directory from which |bpt| will search for source files. +- ``src/hello-bpt/hello-bpt.hpp`` - A simple C++ `header file` +- ``src/hello-bpt/hello-bpt.cpp`` - A single C++ `source file` that contains + uses the header file. + +We won't use these source files just yet. Creating an Application Entrypoint ********************************** -To add a source file to our project, we simply create a file within a source -root with the appropriate file extension. Our source root is ``/src/``, -so we'll place a source file in there. In addition, because we want to create -an *application* we need to designate that the source file provides an -application *entry point*, i.e. a ``main()`` function. To do this, we simply -prepend ``.main`` to the file extension. Create a file:: +To add a `source file` to our project, we simply create a file within a +`source root` with the appropriate `file extension`. Our source root is +``/src/``, so we'll place a source file in there. In addition, because we +want to create an *application* we need to designate that the source file +provides an application *entry point*, i.e. a ``main()`` function. To do this, +we simply prepend ``.main`` to the file extension. Create a file:: -> /src/hello-world.main.cpp +> /src/hello-app.main.cpp and open it in your editor of choice. We'll add the classic C++ *hello, world* program: .. code-block:: c++ :linenos: - :caption: ``/src/hello-world.main.cpp`` + :caption: ``/src/hello-app.main.cpp`` #include @@ -90,8 +106,9 @@ used out-of-the-box, and they'll be suitable for our purposes. built-in toolchain information rather than looking for a toolchain file of that name. -To execute the build, run the ``bpt build`` command as in the following -example, providing the appropriate toolchain name in place of ````:: +To execute the build, run the :doc:`/guide/cli/build` command as in the +following example, providing the appropriate toolchain name in place of +````:: > bpt build -t @@ -102,30 +119,88 @@ For example, if you are using ``gcc``, you would run the command as:: If all is successful, |bpt| will emit information about the compile and link process, and then exit without error. -By default, build results will be placed in a subdirectory of the package root +By default, build results will be placed in a `subdirectory` of the package root named ``_build``. Within this directory, you will find the generated executable -named ``hello-world`` (with a ``.exe`` suffix if on Windows). +named ``hello-app`` (with a ``.exe`` suffix if on Windows). We should now be able to run this executable and see our ``Hello, world!``:: - > ./_build/hello-world + > ./_build/hello-app Hello, world! + +Using Our Headers +***************** + +``bpt new`` created a default header and source file for our projet, but we +aren't using them in our application yet. This can be done by adding an +``#include`` directive to the application's `source file`: + +.. code-block:: c++ + :caption: ``src/hello-app.main.cpp`` + :linenos: + :emphasize-lines: 1 + + #include + + #include + + int main() { + std::cout << "Hello, world!\n"; + } + +The `relative filepath` between the angle brackets of the ``#include`` directive +is resolved relative to the `source root` directory. + +.. note:: + + For detailed information on ``#include`` resolution, refer to information + about the `header search path`. + +This change will ``#include`` our `header file`, but it doesn't make use of it +yet. Since we have included the file, we will now be able to refer to entities +that are declared/defined within it. The default header contains a single +function: ``int hello_bpt::the_answer()``. We can call it and print the return +value to ``std::cout``: + +.. code-block:: c++ + :caption: ``src/hello-app.main.cpp`` + :linenos: + :emphasize-lines: 6,7,8 + + #include + + #include + + int main() { + std::cout << "The answer is: " + << hello_bpt::the_answer() + << '\n'; + } + +We can now ``bpt build`` our program again and see the output:: + + > bpt build -t + # [... elided ...] + > ./_build/hello-app + The answer is: 42 + More Sources ************ -Modularizing our program is good, right? Let's do that. +Inevitably, we'll want more source files to subdivide our program into +easy-to-understand chunks. Adding source files is easy with |bpt|! Add a Header ************ -Create a new subdirectory of ``src``, and we'll call it ``hello``:: +Create a new `subdirectory` of ``src/``. We'll call it ``hello``:: > mkdir src/hello -Within this directory, create a ``strings.hpp``. Edit the content in your -editor of choice: +Within this directory, create a ``strings.hpp`` `header file`. Edit the content +in your editor of choice: .. code-block:: c++ :caption: ``/src/hello/strings.hpp`` @@ -148,11 +223,11 @@ editor of choice: Change our ``main()`` ********************* -Modify the content of ``/src/hello-world.main.cpp`` to include our new +Modify the content of ``/src/hello-app.main.cpp`` to include our new header and to use our ``get_greeting()`` function: .. code-block:: c++ - :caption: ``/src/hello-world.main.cpp`` + :caption: ``/src/hello-app.main.cpp`` :linenos: :emphasize-lines: 1, 6 @@ -172,9 +247,9 @@ If you run the ``bpt build`` command again, you will now see an error: .. code-block:: text - [info ] [bpt-hello] Link: hello-world - [info ] [bpt-hello] Link: hello-world - 57ms - [error] Failed to link executable '/_build/hello-world'. + [info ] [bpt-hello] Link: hello-app + [info ] [bpt-hello] Link: hello-app - 57ms + [error] Failed to link executable '/_build/hello-app'. ... @@ -185,8 +260,8 @@ be haven't *defined it*. Adding Another Compiled Source ****************************** -We'll add another compilable source file to our project. In the same directory -as ``strings.hpp``, add ``strings.cpp``: +We'll add another compilable `source file` to our project. In the same +`directory` as ``strings.hpp``, add ``strings.cpp``: .. code-block:: c++ :caption: ``/src/hello/strings.cpp`` @@ -206,38 +281,15 @@ Run the ``bpt build`` command again, and you'll find that the application successfully compiles and links! If you've used other build systems, you may have noticed a missing step: We -never told |bpt| about our new source file. Actually, we never told |bpt| +never told |bpt| about our new `source file`. Actually, we never told |bpt| about *any* of our source files. We never even told it the name of the executable to generate. What gives? -It turns out, we *did* tell |bpt| all of this information by simply placing -the files on the filesystem with the appropriate file paths. The name of the -executable, ``hello-world``, was inferred by stripping the trailing ``.main`` -from the stem of the filename which defined the entry point. - - -Cleaning Up -*********** - -There's one final formality that should be taken care of before proceeding: -Creating a package manifest file. - -|bpt| will work happily with packages that do not declare themselves, as long -as the filesystem structure is sufficient. However: To use features covered in -later tutorials, we'll need a simple ``bpt.yaml`` file to declare information -about are package. This file should be placed directly in the package root: - -.. code-block:: yaml - :caption: ``/bpt.yaml`` - - name: hello-bpt - version: 0.1.0 - -Rebuilding the project will show no difference at the moment. - -.. note:: - You must use the ``.yaml`` extension for this file. A ``bpt.yml`` will be - ignored. +It turns out, we *did* tell |bpt| all of this information by simply placing the +files on the filesystem with the appropriate filepaths. The name of the +executable, ``hello-app``, was inferred by stripping the trailing ``.main`` from +the `stem ` of the `filepath` of the `source file` which defined the +entry point. .. seealso:: Creating a single application executable is fine and all, but what if we diff --git a/docs/tut/install.rst b/docs/tut/install.rst index d932a1c6..6a4100b6 100644 --- a/docs/tut/install.rst +++ b/docs/tut/install.rst @@ -1,16 +1,17 @@ Getting/Installing |bpt| -########################## +######################## |bpt| ships as a single statically linked executable. It does not have any -installer or distribution package. +installer or distribution package. It has no prerequesites or dependencies that +need to be installed Downloading *********** -Downloads are available on `the main bpt website `_ +Downloads are available on `the main bpt website `_ as well as -`the GitHub Releases page `_. +`the GitHub Releases page `_. Select the executable appropriate for your platform. Alternatively, the appropriate executable can be downloaded directly from the @@ -31,13 +32,15 @@ Or using PowerShell: # Writes a file in the working directory called "bpt.exe" Invoke-WebRequest dds.pizza/get/windows -OutFile bpt.exe -**On Linux, macOS, or other Unix-like systems**, you may need to mark the -downloaded file as executable: +.. note:: -.. code-block:: bash + **On Linux, macOS, or other Unix-like systems**, you may need to mark the + downloaded file as executable: - # Add the executable bit to the file mode for the file named "bpt" - chmod +x bpt + .. code-block:: bash + + # Add the executable bit to the file mode for the file named "bpt" + chmod a+x bpt Installing @@ -54,12 +57,15 @@ command name from any shell interpreter, you will need to place |bpt| on a directory on your shell's ``PATH`` environment variable. +.. _tut.install.install-yourself: + Easy Mode: ``install-yourself`` =============================== -|bpt| includes a subcommand "``install-yourself``" that will move its own -executable to a predetermined directory and ensure that it exists on your -``PATH`` environment variable. It is simple enough to run the command:: +|bpt| includes a subcommand "``install-yourself``" (See: +:doc:`/guide/cli/install-yourself`) that will move its own executable to a +predetermined directory and ensure that it exists on your ``PATH`` environment +variable. It is simple enough to run the command:: $ ./bpt install-yourself @@ -78,15 +84,15 @@ environment variable for your user profile. .. note:: The ``install-yourself`` command accepts some other options. Pass ``--help`` - for more information. + for more information, or see here: :doc:`/guide/cli/install-yourself` Manually: On Unix-like Systems ============================== -For an **unprivileged, user-specific installation (preferred)**, we recommend -placing |bpt| in ``~/.local/bin`` (Where ``~`` represents the ``$HOME`` -directory of the current user). +For an **unprivileged, user-specific installation (preferred)**, it is +recommended to place |bpt| in ``~/.local/bin`` (Where ``~`` represents the +``$HOME`` directory of the current user). Although not officially standardized, `the XDG Base Directory specification `_ From 787a124eaebe658362eb8d0e2202d05a5f260695 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 23 Apr 2022 23:06:56 -0600 Subject: [PATCH 14/62] Many docs updates --- Makefile | 30 +- dag.py | 4 +- docs/conf.py | 23 ++ docs/crs/libraries.rst | 63 +++-- docs/crs/names.rst | 18 ++ docs/design.rst | 11 +- docs/docutils.conf | 2 + docs/err/dup-lib-name.rst | 4 +- docs/err/invalid-pkg-ident.rst | 4 +- docs/err/invalid-pkg-manifest.rst | 9 - docs/err/link-failure.rst | 3 +- docs/err/test-failure.rst | 3 +- docs/guide/apps.rst | 79 ++++++ docs/guide/build-deps.rst | 17 +- docs/guide/cli/opt-out.rst | 9 +- docs/guide/cli/pkg.rst | 1 + docs/guide/index.rst | 5 +- docs/guide/libraries.rst | 252 +++++++++++++++++ docs/guide/packages.rst | 438 ++++++++++-------------------- docs/guide/pkg-cache.rst | 90 ------ docs/guide/source-dists.rst | 68 ----- docs/guide/terms.rst | 139 ++++++++++ docs/guide/tests.rst | 71 +++++ docs/static/styles.css | 27 +- docs/tut/hello-lib.rst | 5 +- 25 files changed, 827 insertions(+), 548 deletions(-) create mode 100644 docs/docutils.conf delete mode 100644 docs/err/invalid-pkg-manifest.rst create mode 100644 docs/guide/apps.rst create mode 100644 docs/guide/libraries.rst delete mode 100644 docs/guide/pkg-cache.rst delete mode 100644 docs/guide/source-dists.rst create mode 100644 docs/guide/tests.rst diff --git a/Makefile b/Makefile index 0e04c624..491fffcf 100644 --- a/Makefile +++ b/Makefile @@ -5,27 +5,15 @@ vagrant-freebsd-ci site alpine-static-ci _alpine-static-ci poetry-setup \ full-ci dev-build release-build -docs: - poetry run dagon docs - echo "Docs generated to _build/docs" - -hugo-docs: - env GEN_FOR_HUGO=1 $(MAKE) docs - -docs-server: docs - echo "Docs are visible on http://localhost:9794/" - cd _build/docs && \ - python -m http.server 9794 - -docs-watch: docs - +poetry run sh tools/docs-watch.sh - -docs-sync-server: - mkdir -p _build/docs - cd _build/docs && \ - browser-sync start --server \ - --reload-delay 300 \ - --watch **/*.html +docs-server: + poetry run sphinx-autobuild \ + -b html \ + -j 8 \ + -Wna \ + --re-ignore "docs/_build" \ + --re-ignore "_build" \ + docs/ \ + _build/docs .poetry.stamp: poetry.lock poetry install --no-dev diff --git a/dag.py b/dag.py index a6383db8..fe675470 100644 --- a/dag.py +++ b/dag.py @@ -1 +1,3 @@ -import bpt_ci.tasks +import importlib + +importlib.import_module('bpt_ci.tasks') diff --git a/docs/conf.py b/docs/conf.py index c1d297eb..dc7122de 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -76,6 +76,29 @@ def intercept_copy_asset(path: str, dest: str, context: Any) -> None: :class: bpt-name .. |bpt| replace:: :bpt-name:`bpt` + +.. |code-open| raw:: html + + + +.. |code-close| raw:: html + + + +.. |bpt.yaml| replace:: |code-open|\ :term:`bpt.yaml`\ |code-close| + +.. |crs.json| replace:: |code-open|\ :ref:`crs.json`\ |code-close| + +.. role:: yaml(code) + :language: yaml + :class: highlight + +.. role:: cpp(code) + :language: cpp + :class: highlight + +.. |#include| replace:: :cpp:`#include` + ''' diff --git a/docs/crs/libraries.rst b/docs/crs/libraries.rst index e6c78d4d..d707a20e 100644 --- a/docs/crs/libraries.rst +++ b/docs/crs/libraries.rst @@ -31,7 +31,7 @@ Terms library path The "path" of a library is a POSIX-style `relative filepath` (relative to - the root of the containing package). The path must name a `library root` + the root of the containing package). The path must name a `CRS library root` within the package. library internal usages @@ -88,16 +88,17 @@ Terms |def-library-usage| - library root + CRS library root The `directory` in which the source files of a single |library| reside. - Contains the ``src/`` and ``include/`` `directories ` for a |library|. + Contains the ``src/`` and ``include/`` `directories ` for a + |library|. .. seealso:: :ref:`The documentation on library roots ` - source root + CRS source root - A subdirectories of the `library root` that contain the source files for a + A subdirectories of the `CRS library root` that contain the source files for a the library (including headers). .. seealso:: `Source Roots`_ @@ -111,11 +112,12 @@ Terms Source files are regular (non-`directory`) files that contain code of some programming language. + header header file A header file (or just "*header*") is kind of `source file` that contains `source code` that is not directly fed to a compiler. It is intended to be - used within other source files via the ``#include`` preprocessor directive. + used within other source files via the |#include| preprocessor directive. Header files usually use a special `file extension` that indicates their being header files. Examples of header file extensions include ``.h`` and @@ -123,16 +125,16 @@ Terms public header root - The subdirectory of the `library root` that contains the header files that - should be exposed to `library users `. + The subdirectory of the `CRS library root` that contains the header files + that should be exposed to `library users `. .. seealso:: `Source Roots`_ private header root - The subdirectory of the `library root` that contains the header files that - are required to compile the respective library, but *should not* be exposed - to the `library users `. + The subdirectory of the `CRS library root` that contains the header files + that are required to compile the respective library, but *should not* be + exposed to the `library users `. It is possible that library does not have a private header root. @@ -140,7 +142,7 @@ Terms compiled source root - The subdirectory of the `library root` that contains the + The subdirectory of the `CRS library root` that contains the `source files ` of the library that must be given to the compiler to generate the library's translation units. @@ -183,16 +185,17 @@ Terms header search path - A filepath from which a compiler will resolve references to header files. + A :term:`filepath` from which a :term:`compiler` will resolve references to + :term:`header files
`. - While the behavior of the ``#include`` directive is implementation-defined, + While the behavior of the |#include| directive is implementation-defined, CRS (and |bpt|) assumes the following behavior: 1. When compiling a source file, the compiler has a list of - :term:`header search path`\ s `L` that it will use to resolve - ``#include`` directives. - 2. An ``#include`` or ``__has_include`` directive specifies a filepath `H` - of the form ``<``\ `H`\ ``>`` + :term:`header search path`\ s `L` that it will use to resolve |#include| + directives. + 2. An |#include| or ``__has_include`` directive specifies a filepath `H` of + the form ``<``\ `H`\ ``>`` 3. For each directory `L_s` in `L`: 1. Create a filepath `H_s` by joining `L_s` and `H` with a directory @@ -221,10 +224,10 @@ The following are the salient attributes of a library within a package: Roots ##### -The `library root` is the directory in which the source files of a single +The `CRS library root` is the directory in which the source files of a single library reside. CRS recognizes two top-level subdirectories within a library root: ``src/`` and ``include/``. A library root must contain one or both of -these directories. Each directory is a `source root`. CRS does not impose any +these directories. Each directory is a `CRS source root`. CRS does not impose any semantics on any other files in the library root. The following semantics apply, based on the presence of ``src/`` and/or @@ -273,7 +276,7 @@ Being *relocatable* in this context means that the location of the directory on the filesystem is irrelevant to the code contained within. As long as the files within a source root are compiled with their `used-libraries ` available, moving or renaming the source root directory should never result in -any ``#include`` directives failing to resolve. +any |#include| directives failing to resolve. Code that explicitly assumes the location of its own source root, including in relation to other source roots, is expressly unsupported by CRS. @@ -318,7 +321,7 @@ Suppose we have a library with the following source files (note the file paths): #include -This library has two `source root` directories: ``include/`` and ``src/``. +This library has two `CRS source root` directories: ``include/`` and ``src/``. ``src/`` is the `private header root` and `compiled source root`, while ``include/`` is the `public header root`. The following applies to each example: @@ -337,7 +340,7 @@ This library has two `source root` directories: ``include/`` and ``src/``. the `private header root` directory, which will be added as a `header search path` while compiling the file. -5. **Okay**: Relative ``#include`` directives that specify a leading ``.`` or +5. **Okay**: Relative |#include| directives that specify a leading ``.`` or ``..`` are unambiguous to the reader, although it is possible that they will still resolve within a different `header search path` than the containing file's own directory. @@ -351,10 +354,10 @@ This library has two `source root` directories: ``include/`` and ``src/``. Public Header Root ****************** -The `public header root` is the `source root` directory that contains headers -that will be visible to the `library's users `. When compiling -the containing library and all of its users, the `public header root` of the -library should be added as a `header search path`. +The `public header root` is the `CRS source root` directory that contains +headers that will be visible to the `library's users `. When +compiling the containing library and all of its users, the `public header root` +of the library should be added as a `header search path`. Transitive usage also applies: If library :math:`A` uses library :math:`B`, and library :math:`B` uses library :math:`C`, the `public header root` of :math:`C` @@ -365,9 +368,9 @@ should be included as a `header search path` while compiling :math:`A`, even if Private Header Root ******************* -The `private header root` is the `source root` directory that contains headers -that should not be visible to the `library's users `, but *will* -be visible while compiling the library's `public translation units`. +The `private header root` is the `CRS source root` directory that contains +headers that should not be visible to the `library's users `, but +*will* be visible while compiling the library's `public translation units`. When compiling the `public translation units`, the `private header root` will be added as a `header search path`. diff --git a/docs/crs/names.rst b/docs/crs/names.rst index bb3158a1..7a561af9 100644 --- a/docs/crs/names.rst +++ b/docs/crs/names.rst @@ -2,6 +2,24 @@ Names ##### +.. default-role:: term + +.. glossary:: + + name + + In `CRS` and |bpt| a *name* refers to a textual identifier matching a + specific form. + + A valid *name* must match the following requirements: + + 1. Must begin with a lowercase ASCII alphabetic character + 2. Must not contain any capital letter characters. + 3. May only contain ASCII alphanumeric characters and the ASCII dot + "``.``", underscore ":literal:`_`", and hyphen "``-``". + 4. Must not contain any adjacent punctuation characters. + 5. Must end with a letter or digit. + A CRS name can be validated by testing against the following regular expression diff --git a/docs/design.rst b/docs/design.rst index 90127085..ef957239 100644 --- a/docs/design.rst +++ b/docs/design.rst @@ -179,12 +179,13 @@ every ``src/`` directory must correspond to *exactly* one library. .. _design.rules.include: -No Arbitrary ``#include`` Directories -===================================== +No Arbitrary |#include| Directories +=================================== -Only ``src/`` and ``include/`` will ever be used as the basis for header -resolution while building a project, so all ``#include`` directives should be -relative to those directories. Refer to :ref:`pkg.source-root`. +Only ``src/`` and ``include/`` will ever be used as the basis for +`header resolution
` while building a project, so all +|#include| directives should be relative to those directories. Refer to +:ref:`libs.source-kinds`. .. _design.rules.uniform-compile: diff --git a/docs/docutils.conf b/docs/docutils.conf new file mode 100644 index 00000000..1bf4d832 --- /dev/null +++ b/docs/docutils.conf @@ -0,0 +1,2 @@ +[restructuredtext parser] +syntax_highlight = short diff --git a/docs/err/dup-lib-name.rst b/docs/err/dup-lib-name.rst index dfaa40fa..ba983c67 100644 --- a/docs/err/dup-lib-name.rst +++ b/docs/err/dup-lib-name.rst @@ -24,5 +24,5 @@ of the same ``name`` in the same ``namespace``. This issue should be raised with the maintainers of the packages in question. .. seealso:: - For more information, refer to the :ref:`pkgs.pkgs` section and the - :ref:`pkgs.libs` section. \ No newline at end of file + + For more information, refer to the :doc:`/guide/libraries` page. diff --git a/docs/err/invalid-pkg-ident.rst b/docs/err/invalid-pkg-ident.rst index 38882de6..165d970a 100644 --- a/docs/err/invalid-pkg-ident.rst +++ b/docs/err/invalid-pkg-ident.rst @@ -6,4 +6,6 @@ Package identifiers in |bpt| must follow a well-defined pattern of ```` follows a few simple rules. .. seealso:: - :ref:`pkgs.pkgs` and :ref:`Package Naming Requirements ` + + - :doc:`/guide/packages` + - :doc:`/crs/names`. diff --git a/docs/err/invalid-pkg-manifest.rst b/docs/err/invalid-pkg-manifest.rst deleted file mode 100644 index 4f5ce790..00000000 --- a/docs/err/invalid-pkg-manifest.rst +++ /dev/null @@ -1,9 +0,0 @@ -Error: Invalid package manifest -############################### - -Every |bpt| package must contain a valid package manifest, which is stored in -JSON5 format in ``package.json5`` (or similarly named file). - -The contents of this file must follow a prescribed content, or |bpt| will -reject the manifest. Refer to the :ref:`pkgs.pkgs` documentation page for more -information about how to declare packages. diff --git a/docs/err/link-failure.rst b/docs/err/link-failure.rst index d5110f65..fcaa1677 100644 --- a/docs/err/link-failure.rst +++ b/docs/err/link-failure.rst @@ -15,8 +15,9 @@ linking model, which we still use to this day, multiple *translation units* known as *linking*. The result of linking is an actual executable. .. note:: + Linking is also used to generate executables that are used as tests. - Refer: :ref:`pkgs.apps-tests`. + Refer: :doc:`/guide/apps` and :doc:`/guide/tests` What is "Linking"? diff --git a/docs/err/test-failure.rst b/docs/err/test-failure.rst index 85e082f5..64f08cf0 100644 --- a/docs/err/test-failure.rst +++ b/docs/err/test-failure.rst @@ -14,4 +14,5 @@ Test execution can be suppressed using the ``--no-tests`` command line option with the ``build`` subcommand. .. seealso:: - Refer to the page on :ref:`pkgs.apps-tests`. \ No newline at end of file + + :doc:`/guide/tests`. diff --git a/docs/guide/apps.rst b/docs/guide/apps.rst new file mode 100644 index 00000000..468fd990 --- /dev/null +++ b/docs/guide/apps.rst @@ -0,0 +1,79 @@ +################################ +Building Applications with |bpt| +################################ + +.. default-role:: term + +|bpt| will recognize certain compilable `source files ` as +belonging to `applications ` (or `tests `), depending on the +`file stem` (the part of the `filename` not including the outer-most +`file extension`). If a compilable source file stem ends with ``.main`` (or +``.test``), that source file is assumed to correspond to an executable to +generate. The filename's second-inner stem before the ``.main`` (or ``.test``) +will be used as the name of the generated executable. + +An "`application` source file" is a `source file` whose `file stem` ends with +``.main``. |bpt| will assume such source files to contain a program entry point +function and not include it as part of the `library`'s archive build. Instead, +when |bpt| is generating the library's applications, the source file will be +compiled, and the resulting object will be linked together with the enclosing +library into an executable. For example: + +- Given ``foo.main.cpp`` + + - The stem is ``foo.main``, which has the extension ``.main``, so we will + generate an `application`. + - The stem of ``foo.main`` is ``foo``, so the executable will be named + ``foo``. + +- Given ``cat-meow.main.cpp`` + + - The stem is ``cat-meow.main``, which has extension ``.main``, so it is an + `application`. + - The stem of ``cat-meow.main`` is ``cat-meow``, so will generate an + executable named ``cat-meow``. + +- Given ``cats.musical.main.cpp`` + + - The stem is ``cats.musical.main``, which has extension ``.main``, so this is + an application. + - The stem of ``cats.musical.main`` is ``cats.musical``, so we will generate + an executable named ``cats.musical``. + - Note that the dot in ``cats.musical`` is not significant, as |bpt| does not + strip any further extensions. + +.. note:: + + |bpt| will automatically append the appropriate `file extension` to the + generated executables based on the host and toolchain. + +The building of library applications can be disabled with the +:option:`--no-apps ` option. + +The application source files of `dependencies ` will be ignored. The +entities defined within application source files will not be included as part of +their enclosing `library`. + + +Output Path +########### + +When an `application` is linked, its output `directory` will be a generated +using a `relative filepath` resolved within the output directory of the build. +The path to the `parent directory ` of the application source file +relative to the `source root` that contains it is used as the subdirectory +within the output directory where the application's executable will be written. + +.. csv-table:: Application Output Path + + Application Source `Filepath`, Executable Output Path + + ``src/app.main.cpp``, ``/app`` + ``src/my-app/app.main.cpp``, ``/my-app/app`` + ``src/somedir/acme-widget-maker.main.cpp``, ``/somedir/acme-widget-marker`` + +.. note:: + + The default build output directory is the ``_build/`` directory within which + |bpt| was invoked. This can be controlled using the + :option:`--out ` option. diff --git a/docs/guide/build-deps.rst b/docs/guide/build-deps.rst index 2111f2fe..80c597f7 100644 --- a/docs/guide/build-deps.rst +++ b/docs/guide/build-deps.rst @@ -38,21 +38,18 @@ Declaring Dependencies ``bpt build-deps`` accepts a list of dependency statements as command line arguments, but it may be useful to specify those requirements in a file. -``bpt build-deps`` accepts a JSON5 file describing the dependencies of a -project as well. This file is similar to a very stripped-down version of a -|bpt| :ref:`package manifest `, and only includes the ``depends`` -key. (The presence of any other key is an error.) +``bpt build-deps`` accepts a JSON5 file describing the dependencies of a project +as well. This file is similar to a very stripped-down version of a |bpt.yaml|, +and only includes the ``dependencies`` key. (The presence of any other key is an +error.) Here is a simple dependencies file that declares a single requirement: .. code-block:: js - :caption: ``dependencies.json5`` + :caption: ``dependencies.yaml`` - { - depends: [ - 'neo-sqlite3^0.2.0', - ] - } + depends: + - neo-sqlite3^0.2.0 Building Dependencies and the Index diff --git a/docs/guide/cli/opt-out.rst b/docs/guide/cli/opt-out.rst index eb9076ba..219827eb 100644 --- a/docs/guide/cli/opt-out.rst +++ b/docs/guide/cli/opt-out.rst @@ -1,6 +1,5 @@ -.. |--out| replace:: - - Specify a :term:`filepath` to the directory where |bpt| will write its build - results and use as scratch space. By default, this will be the ``_build/`` - subdirectory of the working directory. +.. option:: --out , -o + Specify a :term:`filepath` to the `directory` where |bpt| will write its + build results and use as scratch space. By default, this will be the + ``_build/`` subdirectory of the `working directory`. diff --git a/docs/guide/cli/pkg.rst b/docs/guide/cli/pkg.rst index 0f1509c6..ebe37af9 100644 --- a/docs/guide/cli/pkg.rst +++ b/docs/guide/cli/pkg.rst @@ -23,6 +23,7 @@ repositories. .. include:: ./repo-common-args.rst +.. _cli.pkg-create: ``bpt pkg create`` ****************** diff --git a/docs/guide/index.rst b/docs/guide/index.rst index 1620131b..d74dbbae 100644 --- a/docs/guide/index.rst +++ b/docs/guide/index.rst @@ -6,9 +6,10 @@ User Guide cli/index packages + libraries + apps + tests toolchains - source-dists - pkg-cache remote-pkgs interdeps build-deps diff --git a/docs/guide/libraries.rst b/docs/guide/libraries.rst new file mode 100644 index 00000000..ebc35f4b --- /dev/null +++ b/docs/guide/libraries.rst @@ -0,0 +1,252 @@ +Libraries in |bpt| +################## + +.. default-role:: term + +In |bpt|, all code belongs to a `library`, and every library belongs by either a +|bpt| `project` or a `package`. A library can `depend on ` other +libraries within the same project/package and on libraries in external packages. + +Every library in |bpt| has a `name`, and that name must be unique within the +`package` that owns it. + +|bpt| uses the filesystem layout of the library to derive information about it. +Every library has a `library root` directory. A library root contains either +*one* or *two* `source roots ` (``src/`` and/or ``include/``). + +Libraries within `projects ` are defined using |bpt.yaml|. There may be +an implicit `default library`, or some number of +:ref:`explicitly declared libraries ` using the +:yaml:`libs` key of |bpt.yaml|. + +The project's |bpt.yaml| defines the `library roots ` of every +library in the project: + +- If relying on the `default library`, the `library root` is the same as the + `project root` of the project that contains it. +- If using :ref:`explicitly declared libraries `, the + `library root` is defined by a relative path specified using the :yaml:`path` + property of the library declaration in |bpt.yaml|. + +Every library root must contain a ``src/`` directory, *or* an ``include/`` +directory, *or both*. |bpt| will treat both directories as +`source roots `, but behaves differently between the two. + +A single `library root` will always correspond to exactly one library. If the +library has any compilable source files then |bpt| will use those sources to +generate a static library file that is linked into runtime binaries. If a +library contains only headers (a `header-only library`) then |bpt| will not +generate an archive to be included in downstream binaries, but it will still +generate link rules for the dependencies of a header-only library. + + +.. _libs.library-layout: + +Library Layout +************** + +The layout expected by |bpt| is based on the `Pitchfork layout`_ (PFL). |bpt| +does not make use of every provision of the layout document, but the features it +does have are based on PFL. + +.. _Pitchfork layout: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs + +In particular, the ``src/`` and ``include/`` directories are used are used as +`source roots `. + +The smallest subdivision of code that |bpt| recognizes is the `source file`, +which is exactly as it sounds: A single file containing some amount of +`source code`. + +Source files can be grouped on a few axes, the most fundamental of which is +"Is this compiled?" + +|bpt| uses source `file extensions ` to determine whether a +source file should be fed to A `compiler`. All of the common C and C++ file +extensions are supported: + +.. list-table:: + + - * Compiled as C + * ``.c`` + + - * Compiled as C++ + * ``.cpp``, ``.c++``, ``.cc``, and ``.cxx`` + + - * Checked but not compiled (`header files
`) + * ``.h``, ``.h++``, ``.hh``, ``.hpp``, and ``.hxx`` + + - * Not checked or compiled + * ``.ipp``, ``.inc``, and ``.inl`` + +If a file's extension is not listed in the table above, |bpt| will ignore it. +File extensions are case-insensitive for the purpose of this lookup. + +.. note:: + + Although headers are not compiled, this does not mean they are ignored. For + regular `header files
`, |bpt| performs a "compilability check" + on them to ensure that they can be used in isolation. Un-checked + "include-files" such as ``.ipp``, ``.inc``, and ``.inl`` are not checked, but + they are collected together as part of the `package` for distribution. + + +.. _guide.source-roots: + +Source Roots +************ + +.. glossary:: + +`Source files ` are collected as descendents of some *source root* +`directory`. A *source root* is a single directory that contains some *portable* +bundle of source files. The word "portable" is important: It is what +distinguishes the source root from its child directories. + + +Portability +=========== + +By saying that a source root is "portable", we mean that the `directory` itself +can be moved, renamed, or copied without breaking the |#include| directives of +its children or of the directory's referrers. + +As a practical example, let's examine such a directory, which we'll call +``src/`` for the purposes of this example. Suppose we have a such a directory +with the following structure: + +.. code-block:: text + + /src/ + animals/ + mammal/ + mammal.hpp + cat/ + cat.hpp + sound.hpp + sound.cpp + dog/ + dog.hpp + sound.hpp + sound.cpp + +In this example, ``src/`` is a *source root*, but ``src/animals/``, +``src/animals/cat/``, and ``src/animals/dog/`` are **not** source roots. While +they may be directories that contain `source files `, they are not +"roots." + +Suppose now that ``dog.hpp`` contains an |#include| directive: + +.. code-block:: c++ + + #include + +or even a third-party user that wants to use this `library`: + +.. code-block:: c++ + + #include + #include + +In order for any code to compile and resolve these |#include| directives, the +``src/`` directory must be added as a `header search path`. + +Because the |#include| directives are based on the `source root`, and the source +root is *portable*, the exact `filepath` location of the source root directory +is not important to the content of the consuming source code, and can thus be +relocated and renamed as necessary. Consumers only need to update the content of +their `header search path`\ s in a single location rather than modifying their +source code. + +.. note:: + + |bpt| manages header search paths automatically. + + +.. _libs.source-kinds: + +Source Root Kinds +================= + +The naming or `source roots ` determines how |bpt| will treat the +`source files ` in that directory. A source root can be *compiled* +or *header-only*, and *public* or *private*. + +|bpt| distinguishes between a library's *public* `source root`, and a *private* +source root. The `headers
` within the *private* source root are +`private headers` of the library, and the headers within the *public* source +root are the `public headers` of the library. + +When |bpt| is compiling a `library`, both its *private* and its *public* source +roots will be added to the compiler's list of `header search path`\ s. This +allows that library to freely refer to both its *public* and *private* headers. + +On the other hande, when a downstream user of a library :math:`L` is being +compiled, only the *public* source root of that library :math:`L` will be added +as a header search path. This restricts downstream libraries to only have access +to the `public headers` of the libraries that it uses. + +|bpt| supports either one or two source roots in a library. Their naming +determines which directories are treated as *public* or *private*. + +.. rubric:: The Compiled Source Root: ``src/`` + +If the `library root` contains a ``src/`` `directory`, then |bpt| will treat +that directory as the *compiled* `source root`, and will compile any files +within that directory that have an appropriate `file extension`. While compiling +those files, the ``src/`` directory will be given as a `header search path` for +resolving |#include| directives. + +.. note:: + + One can always safely place header files in ``src/``. + +.. rubric:: The *Header-Only* Source Root: ``include/`` + +If the library root contains an ``include/`` `directory`, then that directory +will be treated as the `header`-only `source root`. No files within this +directory will be compiled, but |bpt| will still validate that every file that +has an appropriate `header` `file extension` could be passed to the compiler on +its own. + +.. rubric:: Public vs. Private Source Roots + +If **both** ``src/`` and ``include/`` are present in a `library root`, then +``src/`` will be treated as the *private* `source root` and ``include/`` will be +treated as the *public* source root. Users of the `library` will be able to +resolve the headers in the ``include/`` directory (they are `public headers`), +but not headers in the ``src/`` directory (which are `private headers`). +Additionally: Header files in the ``include/`` directory **will not** be able to +reference any of the private headers in ``src/``, but private headers in +``src/`` will always be able to reference public headers in ``include/``. + +.. warning:: + + Because only the `public headers` are available when compiling library + consumers, it is essential that no headers within the *public* source root + attempt to use `private headers` as they **will not be visible**. + +If **only one of** ``src/`` *or* ``include/`` is present in the `library root`, +that directory will be treated as the public `header` root for the library, and +users will be able to |#include| all headers in the library. There will be no +*private* header root. + +If **only** ``include/`` (**and not** ``src/``) is present in the +`library root`, then |bpt| will treat it as a `header-only library` (No +`source files ` in ``include/`` will be compiled). + +When |bpt| exports a `library` to a `package`, the `header files
` +from the *public* source root will be collected together and distributed as that +library's header tree. The path to the individual header files relative to their +source root will be retained as part of the library distribution. + +By default, |bpt| will compile *all* compilable `source files ` +that appears in the ``src/`` directory. |bpt| will not compile compilable source +files that appear in the ``include/`` directory and will issue a warning if any +such files are found. + +.. note:: + + Some source files will be treated differently based on there name. Refer: + + - :doc:`apps` diff --git a/docs/guide/packages.rst b/docs/guide/packages.rst index 17cf80cf..47aa0fe2 100644 --- a/docs/guide/packages.rst +++ b/docs/guide/packages.rst @@ -1,362 +1,208 @@ -Packages and Layout +################### +Projects & Packages ################### -The units of distribution in |bpt| are *packages*. A single package consists -of one or more *libraries*. In the simplest case, a package will contain a -single library. - -It may be easiest to work from the bottom-up when trying to understand how -|bpt| understands code. - -The layout expected by |bpt| is based on the `Pitchfork layout`_ (PFL). -|bpt| does not make use of every provision of the layout document, but the -features it does have are based on PFL. - -.. _Pitchfork layout: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs - -In particular, the following directories are used: - -- ``src/`` -- ``include/`` -- ``libs/`` -- ``_build/`` (the default build output directory used by |bpt|). - -Note that the ``libs/*/`` directories can contain their own ``src/`` and -``include/`` directories, the purposes and behaviors of which match those of -their top-level counterparts. - - -Source Files -************ - -The smallest subdivision of code that |bpt| recognizes is the *source file*, -which is exactly as it sounds: A single file containing some amount of code. - -Source files can be grouped on a few axes, the most fundamental of which is -"Is this compiled?" - -|bpt| uses source file extensions to determine whether a source file should -be fed to the compiler. All of the common C and C++ file extensions are -supported: - -.. list-table:: - - - * Compiled as C - * ``.c`` and ``.C`` - - - * Compiled as C++ - * ``.cpp``, ``.c++``, ``.cc``, and ``.cxx`` - - - * Not compiled - * ``.H``, ``.H++``, ``.h``, ``.h++``, ``.hh``, ``.hpp``, ``.hxx``, - ``.ipp``, ``.inc``, and ``.inl`` - -If a file's extension is not listed in the table above, |bpt| will ignore it. - -.. note:: - Although headers are not compiled, this does not mean they are ignored. - |bpt| still understands and respects headers, and they are collected - together as part of a *source distribution*. - - -.. _pkgs.apps-tests: - -Applications and Tests -********************** - -|bpt| will recognize certain compilable source files as belonging to -applications and tests, depending on the filenames "stem," which is the part of -the filename not including the outer-most file extension. If a compilable source -filename stem ends with ``.main`` or ``.test``, that source file is assumed to -correspond to an executable to generate. The filename second-inner stem before -the ``.main`` or ``.test`` will be used as the name of the generated executable. -For example: +.. default-role:: term +.. highlight:: yaml -- Given ``foo.main.cpp`` +For |bpt| projects and packages, there are a few important terms to understand: - - The stem is ``foo.main``, whose extension is ``.main``, so we will generate - an application. - - The stem of ``foo.main`` is ``foo``, so the executable will be named - ``foo``. +.. glossary:: -- Given ``bar.test.cpp`` + project - - The stem is ``bar.test``, whose extension is ``.test``, so we will generate - a test. - - The stem of ``bar.test`` is ``bar``, so will generate an executable named - ``bar``. + A |bpt| *project* is a `directory` containing a |bpt.yaml| file and + defines one or more `libraries `. -- Given ``cat-meow.main.cpp`` + Like a `package`, a project has a `name` and a :ref:`version `. For + many purposes, |bpt| will treat a project as a `package` with special + properties. - - The stem is ``cat-meow.main``, which has extension ``.main``, so it is an - application. - - The stem of ``cat-meow.main`` is ``cat-meow``, so will generate an - executable named ``cat-meow``. + |bpt| can capture a project directory as a `package` for distribution and + use in other tools by using the :ref:`cli.pkg-create` subcommand. -- Given ``cats.musical.test.cpp`` + .. seealso:: :ref:`guide.projects` - - The stem is ``cats.musical.test``, which has extension ``.test``, so this is - a text executable. - - The stem of ``cats.musical.test`` is ``cats.musical``, so we will generate - an executable named ``cats.musical``. - - Note that the dot in ``cats.musical`` is not significant, as |bpt| does - strip any further extensions. + package -.. note:: - |bpt| will automatically append the appropriate filename extension to the - generated executables based on the host and toolchain. + A *package* is a `named ` and :ref:`versioned ` collection of + `libraries ` distributed as a unit, available to be "used" to build + additional libraries or `applications `. -An *application* source file is a source file whose file stem ends with -``.main``. |bpt| will assume this source file to contain a program entry -point function and not include it as part of the main library build. Instead, -when |bpt| is generating applications, the source file will be compiled, and -the resulting object will be linked together with the enclosing library into an -executable. + A package contains a |crs.json| file (whereas a `project` would contain a + |bpt.yaml| file). -A *test* source file is a source file whose file stem ends with ``.test``. Like -application sources, a *test* source file is omitted from the main library, and -it will be used to generate tests. The exact behavior of tests is determined by -the ``test_driver`` setting for the package, but the default is that each test -source file will generate a single test executable that is executed by |bpt| -when running unit tests. + When |bpt| is building a dependency solution from some set of dependency + statements, the `name` of the packages are used to create uniqueness: For + every package in a dependency solution, each `name` will only resolve to + only a single version. -The building of tests and applications can be controlled when running -``bpt build``. If tests are built, |bpt| will automatically execute those -tests in parallel once the executables have been generated. + .. seealso:: :term:`CRS package` -In any case, the executables are associated with a *library*, and, when those -executables are linked, the associated library (and its dependencies) will be -linked into the final executable. There is no need to manually specify this -linking behavior. + dependency + A *dependency* specifies a requirement on `libraries ` in an + external `package` in order to build and use the library that has the + dependency. -.. _pkg.source-root: + A dependency specifies the `name` of an external package, a range of + compatible :ref:`versions `, and a list of one or more libraries + from the depended-on package that are required. -Source Roots -************ + In |bpt| (and `CRS`), dependencies are attached to individual + `libraries `, and not to the `package` that contains that library. -Source files are collected as children of some *source root*. A *source -root* is a single directory that contains some *portable* bundle of source -files. The word "portable" is important: It is what distinguishes the -source root from its child directories. + .. seealso:: :term:`CRS dependency` -Portability -=========== +.. _guide.projects: -By saying that a source root is "portable", It indicates that the directory -itself can be moved, renamed, or copied without breaking the ``#include`` -directives of its children or of the directory's referrers. +Understanding Projects +###################### -As a practical example, let's examine such a directory, which we'll call -``src/`` for the purposes of this example. Suppose we have a directory named -``src`` with the following structure: +When using |bpt|, one is most often working within the scope of a `project`. A +`directory` is a |bpt| *project root* if it contains a ``bpt.yaml``: -.. code-block:: text +.. glossary:: - /src/ - animals/ - mammal/ - mammal.hpp - cat/ - cat.hpp - sound.hpp - sound.cpp - dog/ - dog.hpp - sound.hpp - sound.cpp + ``bpt.yaml`` -In this example, ``src/`` is a *source root*, but ``src/animals/``, -``src/animals/cat/``, and ``src/animals/dog/`` are **not** source roots. -While they may be directories that contain source files, they are not "roots." + The ``bpt.yaml`` file is placed in the root `directory` of a `project`. It + defines the `package` attributes of the project, including the `name`, + :ref:`version `, `libraries `, and the + `dependencies ` of those libraries. -Suppose now that ``dog.hpp`` contains an ``#include`` directive: + .. rubric:: Example -.. code-block:: c++ + .. code-block:: yaml + :linenos: - #include + # Required: The name of the project + name: my-example-package + # Required: The version of the project + version: 2.5.1-dev -or even a third-party user that wants to use our library: + # Optional: Dependencies + dependencies: + - boost@1.77.0 using asio, filesystem -.. code-block:: c++ + project root - #include - #include + The *project root* of a project is the `directory` that contains the + project's |bpt.yaml| file. -In order for any code to compile and resolve these ``#include`` directives, the -``src/`` directory must be added to their *include search path*. +A |bpt| `project` roughly corresponds to a source control repository and is the +directory that should be opened and modified with an IDE or text editor. -Because the ``#include`` directives are based on the *portable* source root, -the exact location of ``src/`` is not important to the content of the -consuming source code, and can thus be relocated and renamed as necessary. -Consumers only need to update the path of the *include search path* in a single -location rather than modifying their source code. +Within a |bpt.yaml| file, only the :yaml:`name` and :yaml:`version` keys are +required. -.. _pkgs.source-root: +.. _guide.default-library: -Source Roots in |bpt| -======================= +The Default Library +******************* -To avoid ambiguity and aide in portability, the following rules should be -strictly adhered to: +In |bpt|, all code belongs to a `library`. If a |bpt.yaml| file omits the +:yaml:`libs` property, |bpt| will assume that the `project`'s `default library` +lives in the same directory as |bpt.yaml| and has a library :yaml:`name` +equivalent to the project :yaml:`name`: -#. Source roots may not contain other source roots. -#. Only source roots will be added to the *include-search-path*. -#. All ``#include``-directives are relative to a source root. +.. code-block:: yaml + :caption: |bpt.yaml| -By construction, |bpt| cannot build a project that has nested source roots, -and it will only ever add source roots to the *include-search-path*. + name: acme.widgets + version: 1.2.3 -|bpt| supports either one or two source roots in a library. + # ┌ Implied: ──────────────┐ + │ libs: │ + │ - name: acme.widgets │ + │ path: . │ + # └────────────────────────┘ -.. _pkgs.lib-roots: +The above project definition implies a single default library with the same name +as the project itself: "``acme.widgets``". The `library root` of the default +library is always the same as the `project root`, and cannot be changed. -Library Roots -************* +.. seealso:: -In |bpt|, a *library root* is a directory that contains a ``src/`` directory, -an ``include/`` directory, or both. |bpt| will treat both directories as -source roots, but behaves differently between the two. The ``src/`` and -``include/`` directories are themselves *source roots*. + The :yaml:`libs` property allows one to specify any number of libraries within + the project. The :yaml:`libs` property is discussed below: + :ref:`guide.multiple-libs` -|bpt| distinguishes between a *public* include-directory, and a *private* -include-directory. When |bpt| is compiling a library, both its *private* and -its *public* include-paths will be added to the compiler's -*include-search-path*. When a downstream user of a library is compiling against -a library managed by |bpt|, only the *public* include-directory will be -added to the compiler's *include-search-path*. This has the effect that only -the files that are children of the source root that is the *public* -include-directory will be available when compiling consumers. +.. note:: -.. warning:: - Because only the *public* include-directory is available when compiling - consumers, it is essential that no headers within the *public* - include-directory attempt to use headers from the *private* - include-directory, as they **will not** be visible. + If your project only defines a single library, you are likely to not need to + use :yaml:`libs` and can just rely on the implicit default library. -If both ``src/`` and ``include/`` are present in a library root, then |bpt| -will use ``include/`` as the *public* include-directory and ``src/`` as the -*private* include-directory. If only one of the two is present, then that -directory will be treated as the *public* include-directory, and there will be -no *private* include-directory. +.. note:: -When |bpt| exports a library, the header files from the *public* -include-directory source root will be collected together and distributed as -that library's header tree. The path to the individual header files relative to -their source root will be retained as part of the library distribution. + If the :yaml:`libs` property is specified then |bpt| will not generate a + `default library`. -|bpt| will compile every compilable source file that appears in the ``src/`` -directory. |bpt| will not compile compilable source files that appear in the -``include/`` directory and will issue a warning on each file found. +.. _guide.multiple-libs: -.. _pkgs.libs: +Multiple Libraries in a Project +******************************* -Libraries -********* +Multiple libraries can be specified for a single `project` by using the +top-level :yaml:`libs` property in |bpt.yaml|. :yaml:`libs` must be an array, +and each element must be a map, and each map element must have both a +:yaml:`name` and a :yaml:`path` property: -The *library* is a fundamental unit of consumable code, and |bpt| is -specifically built to work with them. When you are in |bpt|, the library is -the center of everything. +.. code-block:: + :caption: |bpt.yaml| + :emphasize-lines: 4-6 -A single *library root* will always correspond to exactly one library. If the -library has any compilable sources then |bpt| will use those sources to -generate a static library file that is linked into runtime binaries. If a -library contains only headers then |bpt| will not generate an archive to be -included in downstream binaries, but it will still generate link rules for the -dependencies of a header-only library. + name: acme.widgets + version: 1.2.3 -In order for |bpt| to be able to distribute and interlink libraries, a -``library.json5`` file must be present at the corresponding library root. The -only required key in a ``library.json5`` file is ``name``: + libs: + - name: gadgets # Required + path: libs/gadgets # Required -.. code-block:: js +Refer to [`YAML`] for a quick-start on the YAML syntax. If nothing else, you can +use YAML's flow-syntax as an "enhanced `JSON`" that supports :yaml:`# comments` +and unquoted identifier keys:: { - name: 'my-library' + name: "acme.widgets", + version: "1.2.3", + libs: [ + {name: "gadgets", path: "libs/gadgets"}, # Both required + ] } -.. seealso:: More information is discussed on the :ref:`deps.lib-deps` page - - -.. _pkgs.pkg-root: - -Package Roots -************* - -A *package root* is a directory that contains some number of library roots. If -the package root contains a ``src/`` and/or ``include/`` directory then the -package root is itself a library root, and a library is defined at the root of -the package. This is intended to be the most common and simplest method of -creating libraries with |bpt|. +The :yaml:`path` property specifies the `relative filepath` pointing to the +`library root` for the library. This path must be relative to the `project +root` and may only use forward-slash "``/``" as a `directory +separator`. The :yaml:`path` must not "reach outside" of the `project root`. A +path of a single ASCII dot "``.``" refers to the project root itself (This is +the path of the `default library` if :yaml:`libs` is omitted). -If the package root contains a ``libs/`` directory, then each subdirectory of -the ``libs/`` directory is checked to be a library root. Each direct child of -the ``libs/`` directory that is also a library root is added as a child of the -owning package. +Understanding Packages +###################### -.. _pkgs.pkgs: - -Packages -******** - -A package is defined by some *package root*, and contains some number of -*libraries*. - -The primary distribution format of packages that is used by |bpt| is the -*source distribution*. Refer to the page :doc:`source-dists`. +In |bpt| the term "package" refers to a named+versioned collection of +`libraries `. This can include a `project`, but often refers to some +pre-bundled set of files and directories that contains a |crs.json| file. The +contents of |crs.json| declare all of the properties required to consume a +package and the libraries it contains, but you won't often need to interact with +this file directly. Packages are identified by a name/version pair, joined together by an ``@`` -symbol. The version of a package must be a semantic version string. Together, -the ``name@version`` string forms the *package ID*, and it must be unique within -a repository or local package cache. - -In order for a package to be exported by |bpt| it must have a -``package.json5`` file at its package root. Three keys are required to be -present in the ``package.json5`` file: ``name``, ``version``, and ``namespace``: - -.. code-block:: js - - { - name: 'acme-widgets', - version: '6.7.3', - namespace: 'acme', - } - -``version`` must be a valid semantic version string. - -.. note:: - The ``namespace`` key is arbitrary, and not necessarily associated with - any C++ ``namespace``. - -.. seealso:: - The purpose of ``namespace``, as well as additional options in this file, - are described in the :ref:`deps.pkg-deps` page - - -.. _pkgs.naming-reqs: - -Naming Requirements -=================== - -Package names aren't a complete free-for-all. Package names must follow a set -of specific rules: - -- Package names may consist of a subset of ASCII including lowercase - characters, digits, underscores (``_``), hyphens (``-``), and periods - (``.``). - - .. note:: - Different filesystems differ in their handling of filenames. Some platforms - perform unicode and case normalization, which can significantly confuse tools - that don't use the same normalization rules. Different platforms have - different filename limitations and allowable characters. This set of - characters is valid on most currently popular filesystems. - -- Package names must begin with an alphabetic character -- Package names must end with an alphanumeric character (letter or digit). -- Package names may not contain adjacent punctuation characters. +symbol, and with a `package revision number` appended. The version of a package +must be a :ref:`Semantic Version string `. Together, the +``name@version~revision`` string forms the *package ID*, and it must be unique +within a repository. The revision number can often be omitted. + +If you are generating a package from a |bpt| `project` (using the +:ref:`cli.pkg-create` command), the |crs.json| will be synthesized automatically +based on the content of the project's |bpt.yaml| file. + +For this reason a "`project`" can be considered |bpt|'s "high-level" abstraction +of a `package`. A project is intended to be modified directly by an IDE or other +code editor, whereas a package is meant to be consumed by automated tools. diff --git a/docs/guide/pkg-cache.rst b/docs/guide/pkg-cache.rst deleted file mode 100644 index da7770c9..00000000 --- a/docs/guide/pkg-cache.rst +++ /dev/null @@ -1,90 +0,0 @@ -The Local Package Cache -####################### - -|bpt| maintains a local cache of packages that it has obtained at the request -of a user. The packages themselves are stored as -:doc:`source distributions ` (|bpt| does not store the binaries -that it builds within this package cache). - - -Reading Repository Contents -*************************** - -Most times, |bpt| will manage the cache content silently, but it may be useful -to see what |bpt| is currently storing away. - -The content of the cache can be seen with the ``pkg ls`` subcommand:: - -> bpt pkg ls - -This will print the names of packages that |bpt| has downloaded, as well as -the versions of each. - - -Obtaining Packages -****************** - -.. seealso:: See also: :doc:`remote-pkgs` - -When |bpt| builds a package, it will also build the dependency libraries of -that package. In order for the dependency build to succeed, it must have a -local copy of the source distribution of that dependency. - -When |bpt| performs dependency resolution, it will consider both locally -cached packages, as well as packages that are available from any -:doc:`remote packages `. If the dependency solution requires any -packages that are not in the local cache, it will use the information in its -catalog database to obtain a source distribution for each missing package. These -source distributions will automatically be added to the local cache, and later -dependency resolutions will not need to download that package again. - -This all happens automatically when a project is built: There is **no** -"``bpt install``" subcommand. - - -Manually Downloading a Dependency -================================= - -It may be useful to obtain a copy of the source distribution of a package -from a remote. The ``pkg get`` command can be used to do this:: - -> bpt pkg get @ - -This will obtain the source distribution of the package matching the given -package ID and place that distribution in current working directory, using the -package ID as the name of the source distribution directory:: - - $ bpt pkg get spdlog@1.4.2 - [ ... ] - - $ ls . - . - .. - spdlog@1.4.2 - - $ ls ./spdlog@1.4.2/ - include/ - src/ - library.json5 - package.json5 - - -.. _repo.import-local: - -Exporting a Project into the Repository -*************************************** - -|bpt| can only use packages that are available in the local cache. For -packages that have a listing in the catalog, this is not a problem. But if one -is developing a local package and wants to allow it to be used in another local -package, that can be done by importing that project into the package cache as a -regular package, as detailed in :ref:`sdist.import`:: - -> bpt pkg import /path/to/project - -This command will create a source distribution and place it in the local cache. -The package is now available to other projects on the local system. - -.. note:: - This doesn't import in "editable" mode: A snapshot of the package root - will be taken and imported to the local cache. diff --git a/docs/guide/source-dists.rst b/docs/guide/source-dists.rst deleted file mode 100644 index 0a99ba93..00000000 --- a/docs/guide/source-dists.rst +++ /dev/null @@ -1,68 +0,0 @@ -Source Distributions -#################### - -A *source distribution* (often abbreviated as "sdist") is |bpt|'s primary -format for consuming and distributing packages. A source distribution, in -essence, is a :ref:`package root ` that contains only the files -necessary for |bpt| to reproduce the full build of all libraries in the -package. The source distribution retains the directory structure of every -:ref:`source root ` of the original package, and thus retains -the header structure thereof. In this way, the ``#include`` directives to use a -library in a source distribution are identical to if the libraries therein were -directly part of the consuming project. - - -Generating a Source Distribution -******************************** - -Generating a source distribution from a project directory is done with the -``sdist`` subcommand:: - -> bpt pkg create - -The above command can be executed within a package root, and the result will be -a gzip'd tar archive that reproduces the package's filesystem structure, but -only maintaining the files that are necessary for |bpt| to reproduce a build -of that package. - -The ``--project=`` flag can be provided to override the directory that -|bpt| will use as the package root. The default is the current working -directory. - -The ``--out=`` flag can be provided to override the destination path of -the archive. The path should not name an existing file or directory. By default, -|bpt| will generate a source distribution in the working directory with the -pattern ``@.tar.gz``. If the ``--replace`` flag is provided, -then |bpt| will overwrite the destination if it names an existing file or -directory. - - -.. _sdist.import: - -Importing a Source Distribution -******************************* - -Given a source distribution archive, one can import the package into the local -package cache with a single command:: - -> bpt pkg import some-package@1.2.3.tar.gz - -You can also specify an HTTP or HTTPS URL to download a source distribution -archive to import without downloading it separately:: - -> bpt pkg import https://example.org/path/to/sdist.tar.gz - -Alternatively, if a directory correctly models a source distribution, then -that directory can be imported in the same manner:: - -> bpt pkg import /path/to/some/project - -Importing a package will allow projects on the system to use the imported -package as a dependency. - -.. note:: - - If one tries to import a package root into the cache that already contains a - package with a matching identifier, |bpt| will issue an error. This - behavior can be overridden by providing ``--if-exists=replace`` on the - command-line. diff --git a/docs/guide/terms.rst b/docs/guide/terms.rst index 616b5d92..f5d06243 100644 --- a/docs/guide/terms.rst +++ b/docs/guide/terms.rst @@ -7,6 +7,7 @@ Miscellaneous Terminology This page documents miscellaneous terminology used throughout |bpt| and `CRS`. .. glossary:: + :sorted: JSON @@ -104,3 +105,141 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. |bpt| uses some environment variables to control some behavior, such as :envvar:`BPT_LOG_LEVEL` and :envvar:`BPT_NO_DEFAULT_REPO`. + + application + + An *application* is a program that is intended to be run and distributed to + users to perform some set of designated tasks. + + In |bpt|, an application executable is created for each `source file` with + an appropriate `file stem`. + + .. seealso:: :doc:`apps` + + test + + In |bpt|, "test" refers to a `library`-provided execuatble program that can + be used to verify that the library implements the correct behavior. + + Tests are compiled and linked automatically as part of any + :doc:`/guide/cli/build` invocation. + + .. seealso:: :doc:`tests` + + compiler + + A computer program that accepts human-readable `source code` and emits a + lower-level code intended to be executed by a machine. + + default library + + The *default library* of a `project` is the `library` that |bpt| generates + if the :yaml:`libs` project property is omitted in |bpt.yaml|. It will have + the same :yaml:`name` as the project, and its `library root` will be the + same as the `project root`. + + .. note:: + + If the :yaml:`libs` property is specified then |bpt| will not generate a + default library. + + .. seealso:: + + - :ref:`guide.default-library` + - :ref:`guide.multiple-libs` + + header-only library + + A *header-only library* is a `library` that contains no exported compilable + source files, and only contains `header files
`. + + + library root + + The `directory` in which the source files of a single `library` reside. + Contains the ``src/`` and/or ``include/`` directories for that library, each + of which is a `source root`. + + This path is specified using the :yaml:`libs[].path` key of the library in + |bpt.yaml|. + + .. seealso:: + + - :doc:`libraries` + - :ref:`libs.library-layout` + - `CRS library root` + + source root + + A `directory` within a `library` that defines the structure of a source tree + and and acts as a `header search path`. This directory contains + `source files `. + + Within a `library root`, the ``src/`` and ``include/`` directories are + source roots. + + .. seealso:: + + - :ref:`guide.source-roots` + - :ref:`libs.library-layout` + - :ref:`libs.source-kinds` + - :term:`CRS source root` + + public headers + private headers + + Within a `library`, the *public* headers and *private* headers of are the + `header files
` that live in the *public* `source root` or the + *private* source root, respectively. + + The *public* headers are visible to the library's users, but the *private* + headers are only available to the library while compiling the library + itself. + + .. seealso:: :ref:`libs.source-kinds` + + library + + Within the context of software development, a *library* is a set of code + that is designed to be used by other code to build + `applications ` or additional higher-level libraries. + + A library contains a set of definitions of entities that can be used by + other code. This facilitates code reuse. + + A library is the smallest consumable unit of code. That is: You cannot "use" + only a subset of a library when building a library or application. + + .. seealso:: + + - :doc:`libraries` + - :term:`CRS library` + + test dependency + + A *test dependency* is a `dependency` within a `library` that is only used + for compiling and linking the library's `tests `. + + Unlike regular dependencies, test dependencies are **not** *transitive*. + + Test dependencies are declared using the :yaml:`test-dependencies` property + in |bpt.yaml|. + + package ID + + A *package ID* is a string that identifies a package. It is composed of the + package's `name`, :ref:`version `, and the + `package revision number`: + + ``@~`` + + package revision number + + `CRS` allows packages within a repository to be updated without changing the + :ref:`version ` of the package itself. This is reserved for changes + that only update the package metadata or fix critical issues that render + a prior revision to be unusable. The revision number is always a single + positive integer and begins at ``1``. + + The package revision number is visible on the `package ID` as the number + following the tilde ``~`` suffix. diff --git a/docs/guide/tests.rst b/docs/guide/tests.rst new file mode 100644 index 00000000..fc57a3a6 --- /dev/null +++ b/docs/guide/tests.rst @@ -0,0 +1,71 @@ +######################## +Writing Tests with |bpt| +######################## + +.. default-role:: term + +|bpt| will recognize certain compilable `source files ` as +belonging to `tests ` (or `applications `), depending on the +`file stem` (the part of the `filename` not including the outer-most +`file extension`). If a compilable source file stem ends with ``.test`` (or +``.main``), that source file is assumed to correspond to an executable to +generate. The filename's second-inner stem before the ``.test`` (or ``.main``) +will be used as the name of the generated executable. + +A "`test` source file" is a `source file` whose `file stem` ends with ``.test``. +When building a `project`, |bpt| will generate an executable program for each +such source file, compiling and linking it with the enclosing library and the +library's `test dependencies `. The name of the test will be +generated from the next-inner stem of the filename: + +- Given ``bar.test.cpp`` + + - The stem is ``bar.test``, whose extension is ``.test``, so we will generate + a test. + - The stem of ``bar.test`` is ``bar``, so will generate an executable named + ``bar``. + +- Given ``cats.musical.test.cpp`` + + - The stem is ``cats.musical.test``, which has extension ``.test``, so this is + a text executable. + - The stem of ``cats.musical.test`` is ``cats.musical``, so we will generate + an executable named ``cats.musical``. + - Note that the dot in ``cats.musical`` is not significant, as |bpt| does + strip any further extensions. + +.. note:: + + |bpt| will automatically append the appropriate `file extension` to the + generated executables based on the host and toolchain. + +The compiling and linking of a project's tests can be disabled with the +:option:`--no-tests ` option. This will also omit the +project's `test dependencies ` from the dependency solution. + +The test source files of `dependencies ` will be ignored. + + +Output Path +########### + +When a `test` is linked, its output `directory` will be a generated using a +`relative filepath` resolved within the ``test/`` subdirectory of the output +directory of the build. The path to the `parent directory ` of +the test source file relative to the `source root` that contains it is used as +the subdirectory within the ``test/`` directory where the test's executable will +be written. + +.. csv-table:: Application Output Path + + Test Source `Filepath`, Test Executable Output Path + + ``src/checks.test.cpp``, ``/test/checks`` + ``src/my-lib/testing.test.cpp``, ``/test/my-lib/testing`` + ``src/somedir/widgets.test.cpp``, ``/test/somedir/widgets`` + +.. note:: + + The default build output directory is the ``_build/`` directory within which + |bpt| was invoked. This can be controlled using the + :option:`--out ` option. diff --git a/docs/static/styles.css b/docs/static/styles.css index bfcba03e..e17b73bb 100644 --- a/docs/static/styles.css +++ b/docs/static/styles.css @@ -1,12 +1,12 @@ -code.bpt-name.literal > span.pre { +code.bpt-name.literal>span.pre { font-weight: bold; } -p > code.bpt-name.literal > span.pre { +p>code.bpt-name.literal>span.pre { font-size: 14pt; } -code.literal:not(.bpt-name) { +code.literal:not(.bpt-name) { border: 1px solid #0004; padding: 1px 4px; border-radius: 4px; @@ -21,4 +21,25 @@ pre span.linenos { a.hoverxref.tooltip { white-space: nowrap; +} + +code.highlight.yaml span.l-Scalar-Plain:not(.l-Scalar) { + color: #062873; + font-weight: bold; +} + +html .highlight pre .c1 { + color: #1b8799; +} + +div.body h2 { + border-bottom: 2px solid gray; + font-size: 180%; + ; +} + +div.body h3 { + font-style: italic; + border-bottom: 1px solid gray; + font-size: 150%; } \ No newline at end of file diff --git a/docs/tut/hello-lib.rst b/docs/tut/hello-lib.rst index 83eda276..02d6b2b2 100644 --- a/docs/tut/hello-lib.rst +++ b/docs/tut/hello-lib.rst @@ -24,9 +24,8 @@ specifically addressed in the prior example: project. #. |bpt| also supports a top-level directory named ``include/``. Both ``include/`` and ``src/`` may be present in a single library, but there are - some important differences. Refer to :ref:`pkgs.lib-roots` in the layout - guide. -#. A single *library root* may contain any number of applications defined in + some important differences. Refer to :ref:`libs.source-kinds` in the guide. + #. A single *library root* may contain any number of applications defined in ``.main`` files, but a *library root* will correspond to exactly *one* library. Defining additional libraries requires additional packages or adding multiple library roots to a single package. From c76081843fe700893461cfebd7a760d870c7ccf1 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 23 Apr 2022 23:38:14 -0600 Subject: [PATCH 15/62] Update project 'lib' and 'libs' key. Now only 'libraries' --- src/bpt/project/project.walk.cpp | 36 ++++++++------ src/bpt/util/json_walk.hpp | 11 ++++- .../colliding_libs_objects/proj-exec/bpt.yaml | 17 +++---- tests/self-uses-rejected/test_self_uses.py | 19 +------- tests/test_basics.py | 48 +++++++++++++++---- tests/test_pkg_solve.py | 2 +- tests/test_repo/test_repo.py | 7 +-- .../dependents/multi_lib_dependent/bpt.yaml | 2 +- tests/test_uses/partially_buildable/bpt.yaml | 2 +- tests/test_uses/test_uses_test.py | 5 +- tests/test_uses/unbuildable/bpt.yaml | 8 ++-- tools/bpt_ci/testing/__init__.py | 4 +- tools/bpt_ci/testing/fixtures.py | 41 +++++++--------- 13 files changed, 106 insertions(+), 96 deletions(-) diff --git a/src/bpt/project/project.walk.cpp b/src/bpt/project/project.walk.cpp index 289248bd..61fc4d4a 100644 --- a/src/bpt/project/project.walk.cpp +++ b/src/bpt/project/project.walk.cpp @@ -27,14 +27,6 @@ using namespace fansi::literals; namespace { -auto parse_root_lib = [](json5::data::mapping_type data) { - if (data.find("path") != data.end()) { - throw walk_error{"Project's main 'lib' cannot have a 'path' property"}; - } - data.emplace("path", "."); - return project_library::from_json_data(std::move(data)); -}; - auto path_key(std::string_view key, std::optional& into, const std::optional& proj_dir) { @@ -86,8 +78,7 @@ project_manifest::from_json_data(const json5::data& dat "version", "dependencies", "test-dependencies", - "lib", - "libs", + "libraries", "readme", "license-file", "homepage", @@ -100,6 +91,8 @@ project_manifest::from_json_data(const json5::data& dat }; std::vector authors; + bool explicit_libraries = false; + bool has_authors = false; walk(data, require_mapping{"Project manifest root must be a mapping (JSON object)"}, @@ -121,10 +114,9 @@ project_manifest::from_json_data(const json5::data& dat require_array{"Project 'test-dependencies' should be an array"}, for_each{put_into{std::back_inserter(ret.root_test_dependencies), project_dependency::from_json_data}}}, - if_key{"lib", - require_mapping{"Project 'lib' must be a mapping (JSON object)"}, - put_into(std::back_inserter(ret.libraries), parse_root_lib)}, - if_key{"libs", + if_key{"libraries", + set_true{explicit_libraries}, + require_array{"Project 'libraries' should be an array"}, for_each{put_into(std::back_inserter(ret.libraries), project_library::from_json_data)}}, if_key{"$schema", just_accept}, @@ -143,16 +135,30 @@ project_manifest::from_json_data(const json5::data& dat put_into(ret.license, [](std::string s) { return bpt::spdx_license_expression::parse(s); })}, if_key{"authors", + set_true{has_authors}, require_array{"Project 'authors' must be an array of strings"}, for_each{require_str{"Each element of project 'authors' must be a string"}, put_into(std::back_inserter(authors))}}, dym.rejecter(), }); - if (dym.seen_keys.contains("authors")) { + if (has_authors) { ret.authors = std::move(authors); } + if (explicit_libraries) { + if (ret.libraries.empty()) { + throw walk_error{"Project's 'libraries' array may not be empty"}; + } + } else { + // No explicit 'libraries' key: Generate the default library for the + // project: + project_library def; + def.name = ret.name; + def.relpath = "."; + ret.libraries.push_back(std::move(def)); + } + ret.as_crs_package_meta().throw_if_invalid(); return ret; } diff --git a/src/bpt/util/json_walk.hpp b/src/bpt/util/json_walk.hpp index ef294ca1..dd9c60c9 100644 --- a/src/bpt/util/json_walk.hpp +++ b/src/bpt/util/json_walk.hpp @@ -54,7 +54,7 @@ struct key_dym_tracker { template auto rejecter() { - return [this](auto&& key, auto &&) -> semester::walk_result { + return [this](auto&& key, auto&&) -> semester::walk_result { auto unseen = known_keys | std::views::filter([&](auto k) { return !seen_keys.contains(k); }); BOOST_LEAF_THROW_EXCEPTION(E{std::string(key), did_you_mean(key, unseen)}); @@ -63,6 +63,13 @@ struct key_dym_tracker { } }; -struct reject_with_known {}; +struct set_true { + bool& b; + + auto operator()(auto&&) const { + b = true; + return walk.pass; + } +}; } // namespace bpt::walk_utils diff --git a/tests/colliding_libs_objects/proj-exec/bpt.yaml b/tests/colliding_libs_objects/proj-exec/bpt.yaml index a9d3d67c..58b7e2e3 100644 --- a/tests/colliding_libs_objects/proj-exec/bpt.yaml +++ b/tests/colliding_libs_objects/proj-exec/bpt.yaml @@ -1,14 +1,9 @@ { "name": "testing", "version": "1.2.3", - "libs": [ - { - "path": "libs/hello", - "name": "hello" - }, - { - "path": "libs/hello2", - "name": "hello2" - } - ] -} \ No newline at end of file + "libraries": + [ + { "path": "libs/hello", "name": "hello" }, + { "path": "libs/hello2", "name": "hello2" }, + ], +} diff --git a/tests/self-uses-rejected/test_self_uses.py b/tests/self-uses-rejected/test_self_uses.py index ca8a81af..24c25371 100644 --- a/tests/self-uses-rejected/test_self_uses.py +++ b/tests/self-uses-rejected/test_self_uses.py @@ -1,28 +1,13 @@ from bpt_ci.testing import Project, error -def test_self_referential_uses_fails(tmp_project: Project) -> None: - tmp_project.write('src/a.cpp', 'int answer() { return 42; }') - tmp_project.bpt_yaml = { - 'name': 'mylib', - 'version': '0.1.0', - 'lib': { - 'name': 'mine', - 'using': ['mine'] - }, - } - - with error.expect_error_marker_re(r'library-json-cyclic-dependency'): - tmp_project.build() - - def test_self_referential_uses_cycle_fails(tmp_project: Project) -> None: tmp_project.bpt_yaml = { 'name': 'mylib', 'version': '0.1.0', - 'libs': [{ + 'libraries': [{ 'name': 'liba', 'path': 'libs/liba', 'using': ['libb'], @@ -46,7 +31,7 @@ def test_self_referential_uses_for_libs_fails(tmp_project: Project) -> None: tmp_project.bpt_yaml = { 'name': 'mylib', 'version': '0.1.0', - 'libs': [{ + 'libraries': [{ 'name': 'liba', 'path': 'libs/liba', 'using': ['liba'], diff --git a/tests/test_basics.py b/tests/test_basics.py index a7d387e7..302bb366 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -5,7 +5,7 @@ import pytest from bpt_ci import paths from bpt_ci.bpt import BPTWrapper -from bpt_ci.testing import Project, PkgYAML +from bpt_ci.testing import Project, ProjectYAML from bpt_ci.testing.error import expect_error_marker from bpt_ci.testing.fixtures import ProjectOpener from bpt_ci.testing.fs import render_into @@ -50,13 +50,10 @@ def test_simple_lib(tmp_project: Project) -> None: tmp_project.bpt_yaml = { 'name': 'test-project', 'version': '0.0.0', - 'lib': { - 'name': 'test-library', - } } tmp_project.build() assert (tmp_project.build_root / 'compile_commands.json').is_file(), 'compdb was not created' - assert list(tmp_project.build_root.glob('libtest-library.*')) != [], 'No archive was created' + assert list(tmp_project.build_root.glob('libtest-project.*')) != [], 'No archive was created' def test_lib_with_just_test(tmp_project: Project) -> None: @@ -93,7 +90,7 @@ def test_invalid_names(tmp_project: Project) -> None: tmp_project.pkg_create() -TEST_PACKAGE: PkgYAML = { +TEST_PACKAGE: ProjectYAML = { 'name': 'test-pkg', 'version': '0.2.2', } @@ -160,7 +157,7 @@ def test_link_interdep(project_opener: ProjectOpener) -> None: proj.bpt_yaml = { 'name': 'test', 'version': '1.2.3', - 'libs': [{ + 'libraries': [{ 'path': 'foo', 'name': 'foo', }, { @@ -172,7 +169,7 @@ def test_link_interdep(project_opener: ProjectOpener) -> None: proj.build() # Update with a 'using' of the library that was required: - proj.bpt_yaml['libs'][0]['using'] = ['bar'] + proj.bpt_yaml['libraries'][0]['using'] = ['bar'] print(proj.bpt_yaml) # Build is okay now proj.build() @@ -206,3 +203,38 @@ def test_build_other_dir(project_opener: ProjectOpener, tmp_path: Path, bpt: BPT }) proj = Project(Path('./build-other-dir/'), bpt) proj.build(cwd=tmp_path) + + +def test_build_with_explicit_libs_ignores_default_lib(project_opener: ProjectOpener, tmp_path: Path, bpt: BPTWrapper): + render_into( + tmp_path, { + 'src': { + 'bad.cpp': r''' + #error This file is invalid + ''' + }, + 'okay-lib': { + 'src': { + 'okay.cpp': r''' + // This file is okay + ''' + } + } + }) + proj = Project(tmp_path, bpt) + with expect_error_marker('compile-failed'): + proj.build() + + proj.bpt_yaml = { + 'name': 'mine', + 'version': '1.2.3', + } + with expect_error_marker('compile-failed'): + proj.build() + + # Setting an explicit library list does not generate the default library + proj.bpt_yaml['libraries'] = [{ + 'name': 'something', + 'path': 'okay-lib', + }] + proj.build() diff --git a/tests/test_pkg_solve.py b/tests/test_pkg_solve.py index 0c9d40f5..4b7adc45 100644 --- a/tests/test_pkg_solve.py +++ b/tests/test_pkg_solve.py @@ -47,7 +47,7 @@ def _render_pkg_version(name: str, version: str, item: _RepoPackageItem) -> Tree name, 'version': version, - 'libs': [ + 'libraries': [ { 'name': lib_name, 'path': f'libs/{lib_name}', diff --git a/tests/test_repo/test_repo.py b/tests/test_repo/test_repo.py index be4ca350..d78017fb 100644 --- a/tests/test_repo/test_repo.py +++ b/tests/test_repo/test_repo.py @@ -267,7 +267,7 @@ def test_repo_validate_invalid_no_sibling(tmp_crs_repo: CRSRepo, tmp_project: Pr tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', - 'libs': [{ + 'libraries': [{ 'path': '.', 'name': 'foo', 'using': ['bar'], @@ -309,10 +309,7 @@ def test_repo_no_use_invalid_pkg_version(tmp_crs_repo: CRSRepo, tmp_project: Pro tmp_project.bpt_yaml = { 'name': 'foo', 'version': '1.2.3', - 'lib': { - 'name': 'main', - 'dependencies': ['bar@1.2.3'] - }, + 'dependencies': ['bar@1.2.3'], } tmp_project.bpt.run(['pkg', 'solve', '-r', tmp_crs_repo.path, 'bar@1.2.3']) # Replace with a bad pkg_version: diff --git a/tests/test_uses/dependents/multi_lib_dependent/bpt.yaml b/tests/test_uses/dependents/multi_lib_dependent/bpt.yaml index 6e070e05..27a55fed 100644 --- a/tests/test_uses/dependents/multi_lib_dependent/bpt.yaml +++ b/tests/test_uses/dependents/multi_lib_dependent/bpt.yaml @@ -1,6 +1,6 @@ name: "test" version: "0.0.0" -libs: +libraries: - path: "libs/uses" name: "uses" dependencies: ["the_test_lib@0.0.0"] diff --git a/tests/test_uses/partially_buildable/bpt.yaml b/tests/test_uses/partially_buildable/bpt.yaml index 466a1ce3..c1ef9442 100644 --- a/tests/test_uses/partially_buildable/bpt.yaml +++ b/tests/test_uses/partially_buildable/bpt.yaml @@ -1,6 +1,6 @@ name: partially_buildable version: 0.1.0 -libs: +libraries: - path: can_build name: can_build - path: cannot_build diff --git a/tests/test_uses/test_uses_test.py b/tests/test_uses/test_uses_test.py index 3df4d52c..6a530eac 100644 --- a/tests/test_uses/test_uses_test.py +++ b/tests/test_uses/test_uses_test.py @@ -14,7 +14,6 @@ def ut_repo(crs_repo_factory: CRSRepoFactory, test_parent_dir: Path) -> CRSRepo: return repo -# TODO: Do not build test libs if we are not building tests def test_build_lib_with_failing_test_dep(project_opener: ProjectOpener, ut_repo: CRSRepo) -> None: proj = project_opener.open('with_bad_test_dep') # If we disable tests, then we won't try to build the test libraries, and @@ -94,7 +93,7 @@ def test_uses_sibling_lib(tmp_project: Project) -> None: tmp_project.bpt_yaml = { 'name': 'testing', 'version': '1.2.3', - 'libs': [{ + 'libraries': [{ 'name': 'main', 'path': 'main', }, { @@ -109,7 +108,7 @@ def test_uses_sibling_lib(tmp_project: Project) -> None: tmp_project.bpt_yaml = { 'name': 'testing', 'version': '1.2.3', - 'libs': [{ + 'libraries': [{ 'name': 'main', 'path': 'main', }, { diff --git a/tests/test_uses/unbuildable/bpt.yaml b/tests/test_uses/unbuildable/bpt.yaml index c58837da..6f1e1dcf 100644 --- a/tests/test_uses/unbuildable/bpt.yaml +++ b/tests/test_uses/unbuildable/bpt.yaml @@ -1,7 +1,5 @@ { - name: 'unbuildable', - version: '0.0.0', - lib: { - name: "fails_to_build" - } + name: "unbuildable", + version: "0.0.0", + libraries: [{ name: "fails_to_build", path: . }], } diff --git a/tools/bpt_ci/testing/__init__.py b/tools/bpt_ci/testing/__init__.py index 58e9c202..743e769f 100644 --- a/tools/bpt_ci/testing/__init__.py +++ b/tools/bpt_ci/testing/__init__.py @@ -1,11 +1,11 @@ -from .fixtures import Project, ProjectOpener, PkgYAML +from .fixtures import Project, ProjectOpener, ProjectYAML from .fs import dir_renderer, DirRenderer, fs_render_cache_dir from .repo import CRSRepo, CRSRepoFactory __all__ = ( 'Project', 'ProjectOpener', - 'PkgYAML', + 'ProjectYAML', 'dir_renderer', 'DirRenderer', 'fs_render_cache_dir', diff --git a/tools/bpt_ci/testing/fixtures.py b/tools/bpt_ci/testing/fixtures.py index 9e106455..1dd8f0c1 100644 --- a/tools/bpt_ci/testing/fixtures.py +++ b/tools/bpt_ci/testing/fixtures.py @@ -37,13 +37,12 @@ def ensure_absent(path: Pathish) -> None: pass -_PkgYAMLLibraryUsingItem = TypedDict('_PkgYAMLLibraryUsingItem', { +_ProjectYAMLLibraryUsingItem = TypedDict('_ProjectYAMLLibraryUsingItem', { 'lib': str, - 'for': Literal['lib', 'app', 'test'], }) -class _PkgYAMLDependencyItemRequired(TypedDict): +class _ProjectYAMLDependencyItemRequired(TypedDict): dep: str @@ -52,49 +51,41 @@ class _VersionItem(TypedDict): high: str -_PkgYAMLDependencyItemOpt = TypedDict( +_ProjectYAMLDependencyItemOpt = TypedDict( '_ProjectJSONDependencyItemOpt', { 'versions': Sequence[_VersionItem], - 'for': Literal['lib', 'app', 'test'], 'using': Sequence[str], }, total=False, ) -class _PkgYAMLDependencyItemMap(_PkgYAMLDependencyItemRequired, _PkgYAMLDependencyItemOpt): +class _ProjectYAMLDependencyItemMap(_ProjectYAMLDependencyItemRequired, _ProjectYAMLDependencyItemOpt): pass -_PkgYAMLDependencyItem = Union[str, _PkgYAMLDependencyItemMap] +_ProjectYAMLDependencyItem = Union[str, _ProjectYAMLDependencyItemMap] -class _PkgYAMLLibraryItemRequired(TypedDict): +class _ProjectYAMLLibraryItemRequired(TypedDict): name: str path: str -class _PkgYAMLLibraryItem(_PkgYAMLLibraryItemRequired, total=False): - using: Sequence[Union[str, _PkgYAMLLibraryUsingItem]] - dependencies: Sequence[_PkgYAMLDependencyItem] +class _ProjectYAMLLibraryItem(_ProjectYAMLLibraryItemRequired, total=False): + using: Sequence[Union[str, _ProjectYAMLLibraryUsingItem]] + dependencies: Sequence[_ProjectYAMLDependencyItem] -class _MainProjectLibraryItem(TypedDict, total=False): - name: str - dependencies: Sequence[_PkgYAMLDependencyItem] - using: Sequence[Union[str, _PkgYAMLLibraryUsingItem]] - - -class _PkgYAMLRequired(TypedDict): +class _ProjectYAMLRequired(TypedDict): name: str version: str -class PkgYAML(_PkgYAMLRequired, total=False): - dependencies: Sequence[_PkgYAMLDependencyItem] - lib: _MainProjectLibraryItem - libs: Sequence[_PkgYAMLLibraryItem] +class ProjectYAML(_ProjectYAMLRequired, total=False): + dependencies: Sequence[_ProjectYAMLDependencyItem] + libraries: Sequence[_ProjectYAMLLibraryItem] class Library: @@ -231,15 +222,15 @@ def __init__(self, dirpath: Path, bpt: BPTWrapper) -> None: self.build_root = dirpath / '_build' @property - def bpt_yaml(self) -> PkgYAML: + def bpt_yaml(self) -> ProjectYAML: """ Get/set the content of the ``bpt.yaml`` file for the project. """ dat = json.loads(self.root.joinpath('bpt.yaml').read_text()) - return cast(PkgYAML, _WritebackData(self.root.joinpath('bpt.yaml'), dat, dat)) + return cast(ProjectYAML, _WritebackData(self.root.joinpath('bpt.yaml'), dat, dat)) @bpt_yaml.setter - def bpt_yaml(self, data: PkgYAML) -> None: + def bpt_yaml(self, data: ProjectYAML) -> None: self.root.joinpath('bpt.yaml').write_text(json.dumps(data, indent=2)) def lib(self, name: str) -> Library: From 7804733ffd06f24fc4498ef9cb093a3f773a7608 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 24 Apr 2022 00:49:32 -0600 Subject: [PATCH 16/62] "Implicit using all" is no more: No implicit use a lib with the name of the project --- src/bpt/build/builder.cpp | 8 +-- src/bpt/build/plan/library.cpp | 8 +-- src/bpt/cli/cmd/build_common.cpp | 26 ++------ src/bpt/cli/cmd/repo_validate.cpp | 3 +- src/bpt/crs/info/dependency.cpp | 9 +-- src/bpt/crs/info/dependency.hpp | 25 +------- src/bpt/crs/info/package.cpp | 14 +---- src/bpt/crs/info/package.test.cpp | 2 +- src/bpt/project/dependency.cpp | 9 ++- src/bpt/project/dependency.hpp | 2 +- src/bpt/project/dependency.test.cpp | 8 +-- src/bpt/project/dependency.walk.cpp | 14 ++--- src/bpt/solve/solve.cpp | 95 ++++++++--------------------- tests/test_pkg.py | 87 +++++++++++++++++--------- tests/test_pkg_solve.py | 13 ++-- tools/bpt_ci/util.py | 9 +++ 16 files changed, 124 insertions(+), 208 deletions(-) diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index e3b480ef..5da097de 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -91,13 +91,7 @@ build_plan prepare_build_plan(neo::ranges::range_of auto&& sdists) std::function activate_more = [&](const lib_prep_info& inf) { auto add_deps = [&](auto&& deps) { for (const auto& dep : deps) { - // We should never reach this point with implicit usages - neo_assert(invariant, - dep.uses.template is(), - "An implicit-using slipped through to the builder", - inf.lib.name, - dep.name); - for (const auto& use : dep.uses.template as().uses) { + for (const auto& use : dep.uses) { // All libraries that we are using must have been loaded into the builder // (i.e. by the package dependency solver) auto found = all_libs.find(lm::usage{dep.name.str, use.str}); diff --git a/src/bpt/build/plan/library.cpp b/src/bpt/build/plan/library.cpp index 34a21f25..4629d093 100644 --- a/src/bpt/build/plan/library.cpp +++ b/src/bpt/build/plan/library.cpp @@ -77,13 +77,7 @@ library_plan library_plan::create(path_ref pkg_base, } auto pkg_dep_to_usages = [&](crs::dependency const& dep) { - neo_assert(invariant, - dep.uses.is(), - "Expected an explicit usage requirement for dependency object", - dep, - pkg, - lib); - return dep.uses.as().uses | std::views::transform([&](auto&& l) { + return dep.uses | std::views::transform([&](auto&& l) { return lm::usage{dep.name.str, l.str}; }); }; diff --git a/src/bpt/cli/cmd/build_common.cpp b/src/bpt/cli/cmd/build_common.cpp index 096ac2ae..154bcedf 100644 --- a/src/bpt/cli/cmd/build_common.cpp +++ b/src/bpt/cli/cmd/build_common.cpp @@ -24,20 +24,6 @@ using namespace bpt; using namespace fansi::literals; -static void resolve_implicit_usages(crs::package_info& proj_meta, crs::package_info& dep_meta) { - proj_meta.libraries // - | std::views::transform(NEO_TL(_1.dependencies)) // - | std::views::join // - | std::views::filter(NEO_TL(_1.name == dep_meta.id.name)) // - | std::views::transform(NEO_TL(_1.uses)) // - | std::views::filter(NEO_TL(_1.template is())) // - | neo::ranges::each([&](crs::dependency_uses& item) { - item = crs::explicit_uses_list{dep_meta.libraries - | std::views::transform(&bpt::crs::library_info::name) - | neo::to_vector}; - }); -} - builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { sdist_build_params main_params = { .subdir = "", @@ -75,13 +61,11 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { auto sln = bpt::solve(meta_db, crs_deps); for (auto&& pkg : sln) { - auto dep_meta - = fetch_cache_load_dependency(cache, - pkg, - false /* Do not mark libraries to be built */, - builder, - "_deps"); - resolve_implicit_usages(proj_sd.pkg, dep_meta); + fetch_cache_load_dependency(cache, + pkg, + false /* Do not mark libraries to be built */, + builder, + "_deps"); } } diff --git a/src/bpt/cli/cmd/repo_validate.cpp b/src/bpt/cli/cmd/repo_validate.cpp index c7492943..dbbc9094 100644 --- a/src/bpt/cli/cmd/repo_validate.cpp +++ b/src/bpt/cli/cmd/repo_validate.cpp @@ -30,8 +30,7 @@ static bool try_it(const crs::package_info& pkg, crs::cache_db& cache) { auto dep = {crs::dependency{ .name = pkg.id.name, .acceptable_versions = crs::version_range_set{pkg.id.version, pkg.id.version.next_after()}, - .uses = crs::explicit_uses_list{pkg.libraries | std::views::transform(NEO_TL(_1.name)) - | neo::to_vector}, + .uses = pkg.libraries | std::views::transform(NEO_TL(_1.name)) | neo::to_vector, }}; return bpt_leaf_try { fmt::print("Validate package .br.cyan[{}] ..."_styled, pkg.id.to_string()); diff --git a/src/bpt/crs/info/dependency.cpp b/src/bpt/crs/info/dependency.cpp index 2436b3e0..d07d54ab 100644 --- a/src/bpt/crs/info/dependency.cpp +++ b/src/bpt/crs/info/dependency.cpp @@ -76,12 +76,7 @@ std::string bpt::crs::dependency::decl_to_string() const noexcept { } strm << "]"; } - uses.visit(neo::overload{ - [&](implicit_uses_all) { strm << "/*"; }, - [&](explicit_uses_list const& u) { - strm << '/' << joinstr(",", u.uses | std::views::transform(&bpt::name::str)); - }, - }); + strm << '/' << joinstr(",", uses | std::views::transform(&bpt::name::str)); return strm.str(); } @@ -143,7 +138,7 @@ dependency dependency::from_data(const json5::data& data) { pubgrub::interval_set{ver.low(), ver.high()}); } - ret.uses = explicit_uses_list{std::move(uses)}; + ret.uses = std::move(uses); return ret; } diff --git a/src/bpt/crs/info/dependency.hpp b/src/bpt/crs/info/dependency.hpp index 5e104434..83c8848e 100644 --- a/src/bpt/crs/info/dependency.hpp +++ b/src/bpt/crs/info/dependency.hpp @@ -15,29 +15,10 @@ namespace bpt::crs { using version_range_set = pubgrub::interval_set; -struct explicit_uses_list { - std::vector uses; - - bool operator==(explicit_uses_list const&) const noexcept = default; -}; - -struct implicit_uses_all { - bool operator==(const implicit_uses_all&) const noexcept = default; -}; - -struct dependency_uses : bpt::variant_wrapper { - using variant_wrapper::variant_wrapper; - - using variant_wrapper::as; - using variant_wrapper::is; - using variant_wrapper::visit; - using variant_wrapper::operator==; -}; - struct dependency { - bpt::name name; - version_range_set acceptable_versions; - dependency_uses uses; + bpt::name name; + version_range_set acceptable_versions; + std::vector uses; static dependency from_data(const json5::data&); diff --git a/src/bpt/crs/info/package.cpp b/src/bpt/crs/info/package.cpp index c0c418e9..8353a590 100644 --- a/src/bpt/crs/info/package.cpp +++ b/src/bpt/crs/info/package.cpp @@ -84,19 +84,7 @@ std::string package_info::to_json(int indent) const noexcept { })); } json uses = json::array(); - dep.uses.visit(neo::overload{ - [&](explicit_uses_list const& l) { - extend(uses, l.uses | std::views::transform(&bpt::name::str)); - }, - [&](implicit_uses_all) { - neo_assert(invariant, - false, - "We attempted to serialize (to_json) a CRS metadata object that " - "contains an implicit dependency library uses list. This should " - "never occur.", - *this); - }, - }); + extend(uses, dep.uses | std::views::transform(&bpt::name::str)); ret.push_back(json::object({ {"name", dep.name.str}, {"versions", versions}, diff --git a/src/bpt/crs/info/package.test.cpp b/src/bpt/crs/info/package.test.cpp index 766fd802..1d992052 100644 --- a/src/bpt/crs/info/package.test.cpp +++ b/src/bpt/crs/info/package.test.cpp @@ -677,7 +677,7 @@ TEST_CASE("Check parse results") { .acceptable_versions = bpt::crs::version_range_set{semver::version::parse("1.0.0"), semver::version::parse("1.5.1")}, - .uses = bpt::crs::explicit_uses_list{{bpt::name{"baz"}}}, + .uses = {bpt::name{"baz"}}, }}, .test_dependencies ={}, }}, diff --git a/src/bpt/project/dependency.cpp b/src/bpt/project/dependency.cpp index b524a634..a23d9140 100644 --- a/src/bpt/project/dependency.cpp +++ b/src/bpt/project/dependency.cpp @@ -18,8 +18,7 @@ crs::dependency project_dependency::as_crs_dependency() const noexcept { return crs::dependency{ .name = dep_name, .acceptable_versions = acceptable_versions, - .uses = explicit_uses ? crs::dependency_uses{crs::explicit_uses_list{*explicit_uses}} - : crs::dependency_uses{crs::implicit_uses_all{}}, + .uses = using_, }; } @@ -81,6 +80,7 @@ project_dependency project_dependency::from_shorthand_string(const std::string_v adv_token(); if (tok.empty()) { + ret.using_.push_back(ret.dep_name); return ret; } @@ -90,14 +90,13 @@ project_dependency project_dependency::from_shorthand_string(const std::string_v } if (tok == "using") { - ret.explicit_uses.emplace(); while (1) { adv_token(); if (tok == ",") { BOOST_LEAF_THROW_EXCEPTION( e_human_message{"Unexpected extra comma in dependency specifier"}); } - ret.explicit_uses->emplace_back(*bpt::name::from_string(tok)); + ret.using_.emplace_back(*bpt::name::from_string(tok)); if (adv_token() != ",") { break; } @@ -110,4 +109,4 @@ project_dependency project_dependency::from_shorthand_string(const std::string_v } return ret; -} \ No newline at end of file +} diff --git a/src/bpt/project/dependency.hpp b/src/bpt/project/dependency.hpp index 20801f08..00b1dc6f 100644 --- a/src/bpt/project/dependency.hpp +++ b/src/bpt/project/dependency.hpp @@ -27,7 +27,7 @@ struct project_dependency { /// A set of version ranges that are acceptable crs::version_range_set acceptable_versions; /// Libraries from the dependency that will be explicitly used - std::optional> explicit_uses = std::nullopt; + std::vector using_{}; static project_dependency parse_dep_range_shorthand(std::string_view sv); static project_dependency from_shorthand_string(std::string_view sv); diff --git a/src/bpt/project/dependency.test.cpp b/src/bpt/project/dependency.test.cpp index 8a825e55..8cc93e72 100644 --- a/src/bpt/project/dependency.test.cpp +++ b/src/bpt/project/dependency.test.cpp @@ -17,15 +17,15 @@ TEST_CASE("Parse a shorthand") { auto [given, expect] = GENERATE(Catch::Generators::values({ { .given = "foo@1.2.3", - .expect = {{"foo"}, simple_ver_range("1.2.3", "2.0.0")}, + .expect = {{"foo"}, simple_ver_range("1.2.3", "2.0.0"), {bpt::name{"foo"}}}, }, { .given = "foo~1.2.3 ", - .expect = {{"foo"}, simple_ver_range("1.2.3", "1.3.0")}, + .expect = {{"foo"}, simple_ver_range("1.2.3", "1.3.0"), {bpt::name{"foo"}}}, }, { .given = " foo=1.2.3", - .expect = {{"foo"}, simple_ver_range("1.2.3", "1.2.4")}, + .expect = {{"foo"}, simple_ver_range("1.2.3", "1.2.4"), {bpt::name{"foo"}}}, }, { .given = "foo@1.2.3 using bar , baz", @@ -38,7 +38,7 @@ TEST_CASE("Parse a shorthand") { auto dep = REQUIRES_LEAF_NOFAIL(bpt::project_dependency::from_shorthand_string(given)); CHECK(dep.dep_name == expect.dep_name); - CHECK(dep.explicit_uses == expect.explicit_uses); + CHECK(dep.using_ == expect.using_); CHECK(dep.acceptable_versions == expect.acceptable_versions); } #endif diff --git a/src/bpt/project/dependency.walk.cpp b/src/bpt/project/dependency.walk.cpp index 5fe75045..ea841042 100644 --- a/src/bpt/project/dependency.walk.cpp +++ b/src/bpt/project/dependency.walk.cpp @@ -66,19 +66,13 @@ project_dependency project_dependency::from_json_data(const json5::data& data) { }, if_key{"versions", require_array{"Dependency 'versions' must be an array of objects"}, - [&](auto&&) { - got_versions_key = true; - return walk.pass; - }, + set_true{got_versions_key}, for_each{require_mapping{"Each 'versions' element must be an object"}, put_into(std::back_inserter(ver_ranges), parse_version_range)}}, if_key{"using", require_array{"Dependency 'using' must be an array"}, for_each{require_str{"Each dependency 'using' item must be a string"}, - [&](auto&&) { - got_using_key = true; - return walk.pass; - }, + set_true{got_using_key}, put_into(std::back_inserter(explicit_uses), name_from_string{})}}, dym.rejecter(), }); @@ -98,7 +92,9 @@ project_dependency project_dependency::from_json_data(const json5::data& data) { } if (got_using_key) { - ret.explicit_uses = std::move(explicit_uses); + ret.using_ = std::move(explicit_uses); + } else { + ret.using_.push_back(ret.dep_name); } return ret; diff --git a/src/bpt/solve/solve.cpp b/src/bpt/solve/solve.cpp index 2b306a27..d8a5c99a 100644 --- a/src/bpt/solve/solve.cpp +++ b/src/bpt/solve/solve.cpp @@ -45,24 +45,23 @@ semver::version sole_version(const crs::version_range_set& versions) { return (*versions.iter_intervals().begin()).low; } +using name_vec = std::vector; + struct requirement { bpt::name name; crs::version_range_set versions; - dependency_uses uses; + name_vec uses; std::optional pkg_version; explicit requirement(bpt::name name, crs::version_range_set vrs, - dependency_uses u, + name_vec u, std::optional pver) : name{std::move(name)} , versions{std::move(vrs)} , uses{std::move(u)} , pkg_version{pver} { - uses.visit(neo::overload{ - [](explicit_uses_list& l) { sr::sort(l.uses); }, - [](implicit_uses_all) {}, - }); + sr::sort(uses); } static requirement from_crs_dep(const crs::dependency& dep) noexcept { @@ -75,13 +74,7 @@ struct requirement { if (!versions.contains(other.versions)) { return false; } - - if (uses.is() || other.uses.is()) { - return true; - } - auto& my_uses = uses.as().uses; - auto& other_uses = other.uses.as().uses; - if (sr::includes(other_uses, my_uses)) { + if (sr::includes(other.uses, uses)) { return true; } return false; @@ -91,45 +84,16 @@ struct requirement { return versions.disjoint(other.versions); } - dependency_uses union_usages(dependency_uses const& l, - dependency_uses const& r) const noexcept { - return l.visit(neo::overload{ - [&](explicit_uses_list const& left) -> dependency_uses { - return r.visit(neo::overload{ - [&](explicit_uses_list const& right) -> dependency_uses { - explicit_uses_list uses_union; - sr::set_union(left.uses, right.uses, std::back_inserter(uses_union.uses)); - return uses_union; - }, - [](implicit_uses_all a) -> dependency_uses { return a; }, - }); - }, - [&](implicit_uses_all) -> dependency_uses { return r; }, - }); + name_vec union_usages(name_vec const& l, name_vec const& r) const noexcept { + name_vec uses_union; + sr::set_union(l, r, std::back_inserter(uses_union)); + return uses_union; } - dependency_uses intersect_usages(dependency_uses const& l, - dependency_uses const& r) const noexcept { - return l.visit(neo::overload{ - [&](explicit_uses_list const& left) -> dependency_uses { - return r.visit(neo::overload{ - [&](explicit_uses_list const& right) -> dependency_uses { - explicit_uses_list uses_intersection; - sr::set_intersection(left.uses, - right.uses, - std::back_inserter(uses_intersection.uses)); - return uses_intersection; - }, - [&](implicit_uses_all) -> dependency_uses { return l; }, - }); - }, - [&](implicit_uses_all) -> dependency_uses { return r; }, - }); - } - - bool uses_is_empty(dependency_uses const& u) const noexcept { - return u.visit(neo::overload([](implicit_uses_all) { return true; }, - [](explicit_uses_list const& e) { return e.uses.empty(); })); + name_vec intersect_usages(name_vec const& l, name_vec const& r) const noexcept { + name_vec uses_intersection; + sr::set_intersection(l, r, std::back_inserter(uses_intersection)); + return uses_intersection; } std::optional intersection(const requirement& other) const noexcept { @@ -151,7 +115,7 @@ struct requirement { std::optional difference(const requirement& other) const noexcept { auto range = versions.difference(other.versions); - if (range.empty() and (uses_is_empty(uses) or uses == other.uses)) { + if (range.empty() and (uses.empty() or uses == other.uses)) { return std::nullopt; } return requirement{name, std::move(range), union_usages(uses, other.uses), std::nullopt}; @@ -204,20 +168,15 @@ struct metadata_provider { if (!req.versions.contains(entry.pkg.id.version)) { return false; } - return req.uses.visit(neo::overload{ - [&](crs::implicit_uses_all) { return true; }, - [&](crs::explicit_uses_list const& u) { - bool has_all_libraries = sr::all_of(u.uses, [&](auto&& uses_name) { - return sr::any_of(entry.pkg.libraries, NEO_TL(uses_name == _1.name)); - }); - if (!has_all_libraries) { - bpt_log(debug, - " Near match: {} (missing one or more required libraries)", - entry.pkg.id.to_string()); - } - return has_all_libraries; - }, + bool has_all_libraries = sr::all_of(req.uses, [&](auto&& uses_name) { + return sr::any_of(entry.pkg.libraries, NEO_TL(uses_name == _1.name)); }); + if (!has_all_libraries) { + bpt_log(debug, + " Near match: {} (missing one or more required libraries)", + entry.pkg.id.to_string()); + } + return has_all_libraries; }); if (cand == pkgs.cend()) { @@ -254,13 +213,7 @@ struct metadata_provider { auto pkg = it->pkg; std::set uses; - req.uses.visit( - neo::overload{[&](crs::explicit_uses_list const& u) { extend(uses, u.uses); }, - [&](crs::implicit_uses_all) { - extend(uses, - pkg.libraries | stdv::transform(&crs::library_info::name)); - }}); - + extend(uses, req.uses); std::set more_uses; while (1) { more_uses = uses; diff --git a/tests/test_pkg.py b/tests/test_pkg.py index 545a1c45..e4a126f0 100644 --- a/tests/test_pkg.py +++ b/tests/test_pkg.py @@ -2,11 +2,12 @@ import tarfile import pytest from pathlib import Path -from typing import Tuple + import platform from bpt_ci.bpt import BPTWrapper from bpt_ci.testing import ProjectOpener, Project, error, CRSRepo +from bpt_ci.util import read_tarfile_member @pytest.fixture() @@ -101,36 +102,62 @@ def test_pkg_spdx(tmp_project: Project) -> None: def test_pkg_create_almost_valid(tmp_project: Project) -> None: - tmp_project.write( - 'pkg.json', - json.dumps({ - "name": - "catch2", - "version": - "2.13.6", - "pkg-version": - 1, - "libraries": [{ - "name": "catch2", - "path": ".", - "using": [], - "test-using": [], - "dependencies": [], - "test-dependencies": [] - }, { - "name": "main", - "path": "libs/main", - "test-dependencies": [], - "dependencies": [], - "test-using": [], - "using": [{ - "lib": "catch2" - }] - }], - "schema-version": - 1 - })) + pkg_data = { + "name": + "catch2", + "version": + "2.13.6", + "pkg-version": + 1, + "libraries": [{ + "name": "catch2", + "path": ".", + "using": [], + "test-using": [], + "dependencies": [], + "test-dependencies": [] + }, { + "name": "main", + "path": "libs/main", + "test-dependencies": [], + "dependencies": [], + "test-using": [], + "using": [{ + "lib": "catch2" + }] + }], + "schema-version": + 1 + } + tmp_project.write('pkg.json', json.dumps(pkg_data)) with error.expect_error_marker('invalid-pkg-json'): tmp_project.build() with error.expect_error_marker('invalid-pkg-json'): tmp_project.pkg_create() + + pkg_data['libraries'][1]['using'] = ['catch2'] + tmp_project.root.joinpath('libs/main').mkdir(parents=True) + tmp_project.write('pkg.json', json.dumps(pkg_data)) + tmp_project.build() + tmp_project.pkg_create() + + +def test_pkg_create_default_using(tmp_project: Project): + tmp_project.bpt_yaml = {'name': 'foo', 'version': '1.2.3', 'dependencies': ['bar@4.1.3']} + tmp_project.pkg_create() + pkg_json = json.loads(read_tarfile_member(tmp_project.build_root / 'foo@1.2.3~1.tar.gz', 'pkg.json')) + assert pkg_json['libraries'][0] == { + 'name': 'foo', + 'path': '.', + 'using': [], + 'test-using': [], + 'test-dependencies': [], + 'dependencies': [{ + 'name': 'bar', + 'versions': [{ + 'low': '4.1.3', + 'high': '5.0.0' + }], + 'using': ['bar'], + }] + } diff --git a/tests/test_pkg_solve.py b/tests/test_pkg_solve.py index 4b7adc45..6956a532 100644 --- a/tests/test_pkg_solve.py +++ b/tests/test_pkg_solve.py @@ -247,18 +247,15 @@ def test_solve_transitive_req_requires_lib_conflict(solve_repo_1: QuickRepo) -> def test_solve_unsolvable_version_diamond(solve_repo_1: QuickRepo): with expect_solve_fail(): - solve_repo_1.pkg_solve('pkg-unsolvable-version-diamond@1.2.3') + solve_repo_1.pkg_solve('pkg-unsolvable-version-diamond@1.2.3 using main') def test_solve_unsolvable_lib_diamond(solve_repo_1: QuickRepo): with expect_solve_fail(): - solve_repo_1.pkg_solve('pkg-unsolvable-lib-diamond@1.2.3') + solve_repo_1.pkg_solve('pkg-unsolvable-lib-diamond@1.2.3 using main') def test_solve_ignore_unsolvable_libs(solve_repo_1: QuickRepo) -> None: - # No error: We aren't depending on the 'nonesuch' library - with expect_solve_fail(): - solve_repo_1.pkg_solve('pkg-with-unsolvable-library@1.2.3') solve_repo_1.pkg_solve('pkg-with-unsolvable-library@1.2.3 using goodlib') with expect_solve_fail(): solve_repo_1.pkg_solve('pkg-with-unsolvable-library@1.2.3 using badlib') @@ -266,15 +263,15 @@ def test_solve_ignore_unsolvable_libs(solve_repo_1: QuickRepo) -> None: def test_solve_skip_unsolvable_version(solve_repo_1: QuickRepo) -> None: with expect_solve_fail(): - solve_repo_1.pkg_solve('pkg-with-unsolvable-version=1.2.3') + solve_repo_1.pkg_solve('pkg-with-unsolvable-version=1.2.3 using main') # Okay: Just pull bar@1.2.4 - solve_repo_1.pkg_solve('pkg-with-unsolvable-version@1.2.3') + solve_repo_1.pkg_solve('pkg-with-unsolvable-version@1.2.3 using main') def test_solve_fail_with_transitive_no_such_lib(solve_repo_1: QuickRepo) -> None: # Error: No 'bar' has 'no-such-lib' with expect_solve_fail(): - solve_repo_1.pkg_solve('pkg-transitive-no-such-lib@1.2.3') + solve_repo_1.pkg_solve('pkg-transitive-no-such-lib@1.2.3 using main') def test_solve_conflicting_libset_2(solve_repo_1: QuickRepo) -> None: diff --git a/tools/bpt_ci/util.py b/tools/bpt_ci/util.py index ee1e412c..bb63f7e1 100644 --- a/tools/bpt_ci/util.py +++ b/tools/bpt_ci/util.py @@ -1,9 +1,18 @@ from pathlib import PurePath from typing import Union, MutableSequence, MutableMapping +import tarfile + #: A path, string, or convertible-to-Path object Pathish = Union[PurePath, str] JSONishValue = Union[None, float, str, bool, MutableSequence['JSONishValue'], MutableMapping[str, 'JSONishValue']] JSONishDict = MutableMapping[str, JSONishValue] JSONishArray = MutableSequence[JSONishValue] + + +def read_tarfile_member(tarpath: Pathish, member: Pathish) -> bytes: + with tarfile.open(tarpath, 'r:*') as tf: + io = tf.extractfile(str(PurePath(member).as_posix())) + assert io, f'No member of [{tarpath}]: [{member}]' + return io.read() From 37d00c3c9d05988032336baaa1663b258efade60 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 24 Apr 2022 00:49:48 -0600 Subject: [PATCH 17/62] Fix unit test project --- data/projects/simple/bpt.yaml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/data/projects/simple/bpt.yaml b/data/projects/simple/bpt.yaml index 84271ef3..54f99f6b 100644 --- a/data/projects/simple/bpt.yaml +++ b/data/projects/simple/bpt.yaml @@ -1,7 +1,9 @@ +# prettier-ignore { "name": "simple", "version": "1.2.3", - "lib": { - "name": "simple" - } -} \ No newline at end of file + "libraries": [{ + "name": "simple", + "path": "." + }], +} From f7e6539da628c22acece52809479724dc0c2e462 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 30 Apr 2022 20:49:50 -0600 Subject: [PATCH 18/62] Full options to 'bpt new', better output colors --- src/bpt.main.cpp | 22 ++++++----- src/bpt/cli/cmd/new.cpp | 84 +++++++++++++++++++++++++++++++---------- src/bpt/cli/options.cpp | 10 +++-- src/bpt/cli/options.hpp | 2 + src/debate/argument.cpp | 40 +++++++++++++++++++- src/debate/argument.hpp | 24 +++++++++++- tests/test_basics.py | 6 +++ 7 files changed, 151 insertions(+), 37 deletions(-) diff --git a/src/bpt.main.cpp b/src/bpt.main.cpp index b9cc4648..4329fe5c 100644 --- a/src/bpt.main.cpp +++ b/src/bpt.main.cpp @@ -80,7 +80,7 @@ int main_fn(std::string_view program_name, const std::vector& argv) debate::e_invalid_arg_value val) { std::cerr << p.value.usage_string(program_name) << '\n'; fmt::print(std::cerr, - "Invalid {} value '{}' given for '{}'\n", + "Invalid .cyan[{}] value \".bold.red[{}]\" given for '.yellow[{}]'\n"_styled, arg.value.valname, val.value, spell.value); @@ -93,17 +93,19 @@ int main_fn(std::string_view program_name, const std::vector& argv) debate::e_wrong_val_num given) { std::cerr << p.value.usage_string(program_name) << '\n'; if (arg.value.nargs == 0) { - fmt::print(std::cerr, - "Argument '{}' does not expect any values, but was given one\n", - spell.value); + fmt::print( + std::cerr, + "Argument .yellow[{}] does not expect any values, but was given one\n"_styled, + spell.value); } else if (arg.value.nargs == 1 && given.value == 0) { - fmt::print(std::cerr, - "Argument '{}' expected to be given a value, but received none\n", - spell.value); + fmt::print( + std::cerr, + "Argument .yellow[{}] expected to be given a value, but received none\n"_styled, + spell.value); } else { fmt::print( std::cerr, - "Wrong number of arguments provided for '{}': Expected {}, but only got {}\n", + "Wrong number of arguments provided for .yellow[{}]: Expected {}, but only got {}\n"_styled, spell.value, arg.value.nargs, given.value); @@ -112,14 +114,14 @@ int main_fn(std::string_view program_name, const std::vector& argv) }, [&](debate::missing_required, debate::e_argument_parser p, debate::e_argument arg) { fmt::print(std::cerr, - "{}\nMissing required argument '{}'\n", + "{}\nMissing required argument '.yellow[{}]'\n"_styled, p.value.usage_string(program_name), arg.value.preferred_spelling()); return 2; }, [&](debate::invalid_repetition, debate::e_argument_parser p, debate::e_arg_spelling sp) { fmt::print(std::cerr, - "{}\nArgument '{}' cannot be provided more than once\n", + "{}\nArgument '.yellow[{}]' cannot be provided more than once\n"_styled, p.value.usage_string(program_name), sp.value); return 2; diff --git a/src/bpt/cli/cmd/new.cpp b/src/bpt/cli/cmd/new.cpp index 94d7e94c..ae7c5993 100644 --- a/src/bpt/cli/cmd/new.cpp +++ b/src/bpt/cli/cmd/new.cpp @@ -52,6 +52,51 @@ std::string to_ident(std::string_view given) { return ret; } +const std::string_view BPT_YAML_TEMPLATE = R"(# Project '{0}' created by 'bpt new' +name: {0} +version: 0.1.0 + +## Use 'dependencies' to declare dependencies on external libraries +# dependencies: +# - fmt@8.1.1 + +## Use 'test-dependencies' to declare dependencies on external libraries to be +## used by this project's tests +# test-dependencies: +# - catch2@2.13.9 using main + +## The relative filepath to the project's README file +readme: README.md + +## Provide a very brief description of the project +description: | + The is the {0} project. Hello! + +## Point to the project's homepage on the web +# homepage: example.com + +## The source-control repository of the project +# repository: example.com/{0}/source + +## A URL to the documentation for the project +# documentation: example.com/{0}/docs + +## Specify an SPX License ID for the project +# license: + +## List the authors of the project +# authors: +# - My Name +# - Other Name +)"; + +const std::string_view README_MD_TEMPLATE = R"( +# `{0}` - A Great New Project + +Add introductory information about your project to this file, which will likely +be the first thing that potential new users will see. +)"; + } // namespace int new_cmd(const options& opts) { @@ -97,31 +142,29 @@ int new_cmd(const options& opts) { } bool split_dir = false; - while (true) { - auto got = get_argument( - "Split headers and sources into [include/] and [src/] directories? [y/N]", - std::nullopt, - ""); - if (got == neo::oper::any_of("n", "N", "no", "")) { - split_dir = false; - break; - } else if (got == neo::oper::any_of("y", "Y", "yes")) { - split_dir = true; - break; - } else { - fmt::print(std::cerr, "Enter one of '.bold.cyan[y]' or '.bold.cyan[n]'"_styled); + if (opts.new_.split_src_include.has_value()) { + split_dir = *opts.new_.split_src_include; + } else { + while (true) { + auto got = get_argument( + "Split headers and sources into [include/] and [src/] directories? [y/N]", + std::nullopt, + ""); + if (got == neo::oper::any_of("n", "N", "no", "")) { + split_dir = false; + break; + } else if (got == neo::oper::any_of("y", "Y", "yes")) { + split_dir = true; + break; + } else { + fmt::print(std::cerr, "Enter one of '.bold.cyan[y]' or '.bold.cyan[n]'"_styled); + } } } fs::path project_dir = dest; fs::create_directories(project_dir); - bpt::write_file(project_dir / "bpt.yaml", - fmt::format("# Project '{0}' created by 'bpt new'\n" - "name: {0}\n" - "version: 0.1.0\n" - "lib:\n" - " name: {0}\n", - name)); + bpt::write_file(project_dir / "bpt.yaml", fmt::format(BPT_YAML_TEMPLATE, name)); fs::path header_dir = split_dir ? (project_dir / "include") : (project_dir / "src"); fs::path src_dir = project_dir / "src"; @@ -143,6 +186,7 @@ int new_cmd(const options& opts) { "}}\n", to_ident(name))); + bpt::write_file(project_dir / "README.md", fmt::format(README_MD_TEMPLATE, name)); fmt::print("New project files written to [.bold.cyan[{}]]\n"_styled, dest); return 0; } diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 27a52a8e..4b8ad5ee 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -440,16 +440,18 @@ struct setup { .valname = "", .action = put_into(opts.new_.name), }); - // parser.add_argument({ - // .long_spellings = {"name"}, - // .action = store_value(opts.new_.name), - // }); parser.add_argument({ .long_spellings = {"dir"}, .help = "Directory in which the project will be generated", .valname = "", .action = put_into(opts.new_.directory), }); + parser.add_argument({ + .long_spellings = {"split-src-include"}, + .help = "Whether to split the [src/] and [include/] directories", + .valname = "{true,false}", + .action = parse_bool_into(opts.new_.split_src_include), + }); } }; diff --git a/src/bpt/cli/options.hpp b/src/bpt/cli/options.hpp index eb1f2406..462162f9 100644 --- a/src/bpt/cli/options.hpp +++ b/src/bpt/cli/options.hpp @@ -244,6 +244,8 @@ struct options { opt_string directory; /// The name of the new project opt_string name; + /// Whether to split sources/headers + std::optional split_src_include; } new_; /** diff --git a/src/debate/argument.cpp b/src/debate/argument.cpp index cefd7b29..e7c438ca 100644 --- a/src/debate/argument.cpp +++ b/src/debate/argument.cpp @@ -1,6 +1,7 @@ #include "./argument.hpp" #include +#include #include @@ -48,8 +49,8 @@ std::string argument::syntax_string() const noexcept { std::string ret; auto pref_spell = preferred_spelling(); auto real_valname = !valname.empty() - ? valname - : (long_spellings.empty() ? "" : ("<" + long_spellings[0] + ">")); + ? valname + : (long_spellings.empty() ? "" : ("<" + long_spellings[0] + ">")); if (is_positional()) { if (required) { if (can_repeat) { @@ -122,3 +123,38 @@ std::string argument::help_string() const noexcept { return ret; } + +bool debate::parse_bool_string(std::string_view sv) { + if (sv + == neo::oper::any_of("y", // + "Y", + "yes", + "YES", + "Yes", + "true", + "TRUE", + "True", + "on", + "ON", + "On", + "1")) { + return true; + } else if (sv + == neo::oper::any_of("n", + "N", + "no", + "NO", + "No", + "false", + "FALSE", + "False", + "off", + "OFF", + "Off", + "0")) { + return false; + } else { + BOOST_LEAF_THROW_EXCEPTION(invalid_arguments("Invalid string for boolean/toggle option"), + e_invalid_arg_value{std::string(sv)}); + } +} diff --git a/src/debate/argument.hpp b/src/debate/argument.hpp index b3c64916..966f8502 100644 --- a/src/debate/argument.hpp +++ b/src/debate/argument.hpp @@ -3,6 +3,7 @@ #include "./error.hpp" #include +#include #if __has_include() #include "./enum.hpp" @@ -19,6 +20,8 @@ namespace debate { template constexpr auto make_enum_putter(E& dest) noexcept; +bool parse_bool_string(std::string_view sv); + template class argument_value_putter { T& _dest; @@ -30,6 +33,17 @@ class argument_value_putter { void operator()(std::string_view value, std::string_view) { _dest = T(value); } }; +template +class argument_value_putter> { + std::optional& _dest; + +public: + explicit argument_value_putter(std::optional& opt) + : _dest(opt) {} + + void operator()(std::string_view value, std::string_view) { _dest = static_cast(value); } +}; + template class integer_putter { Int& _dest; @@ -67,7 +81,15 @@ constexpr inline auto store_value = [](auto& dest, auto val) { constexpr inline auto store_true = [](auto& dest) { return store_value(dest, true); }; constexpr inline auto store_false = [](auto& dest) { return store_value(dest, false); }; -constexpr inline auto put_into = [](auto& dest) { return make_argument_putter(dest); }; +constexpr inline auto parse_bool_into = [](auto& dest) { + return [&dest](std::string_view given, std::string_view spell) -> void { + auto _ = boost::leaf::on_error(e_arg_spelling{std::string(spell)}); + dest = parse_bool_string(given); + }; +}; + +constexpr inline auto put_into + = [](auto& dest) { return make_argument_putter(dest); }; constexpr inline auto push_back_onto = [](auto& dest) { return [&dest](std::string_view value, std::string_view = {}) { dest.emplace_back(value); }; diff --git a/tests/test_basics.py b/tests/test_basics.py index 302bb366..a8ea677b 100644 --- a/tests/test_basics.py +++ b/tests/test_basics.py @@ -238,3 +238,9 @@ def test_build_with_explicit_libs_ignores_default_lib(project_opener: ProjectOpe 'path': 'okay-lib', }] proj.build() + + +def test_new_then_build(bpt: BPTWrapper, tmp_path: Path) -> None: + bpt.run(['new', 'test-project', '--dir', tmp_path, '--split-src-include=no']) + proj = Project(tmp_path, bpt) + proj.build() From 5bf3af728b69475b1899a81fe15f846c27da51f6 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 30 Apr 2022 21:03:10 -0600 Subject: [PATCH 19/62] Fix: Add 'using' sibling libraries to build plan --- src/bpt/build/builder.cpp | 46 +++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index 5da097de..6c96c976 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -92,20 +92,38 @@ build_plan prepare_build_plan(neo::ranges::range_of auto&& sdists) auto add_deps = [&](auto&& deps) { for (const auto& dep : deps) { for (const auto& use : dep.uses) { - // All libraries that we are using must have been loaded into the builder - // (i.e. by the package dependency solver) - auto found = all_libs.find(lm::usage{dep.name.str, use.str}); - neo_assert(invariant, - found != all_libs.end(), - "Failed to find a dependency library for build activation", - inf.lib.name, - dep.name, - use); - bool did_add = libs_to_build.emplace(&found->second).second; - if (did_add) { - // Recursively activate more libraries used by this library. - activate_more(found->second); - } + std::function add_named + = [&](bpt::name const& libname) { + // All libraries that we are using must have been loaded into the + // builder (i.e. by the package dependency solver) + auto found = all_libs.find(lm::usage{dep.name.str, libname.str}); + neo_assert(invariant, + found != all_libs.end(), + "Failed to find a dependency library for build activation", + inf.lib.name, + dep.name, + libname); + bool did_add = libs_to_build.emplace(&found->second).second; + if (did_add) { + bpt_log(trace, + "Activate library [{}/{}] (Required by {}/{})", + dep.name, + libname, + inf.pkg.id.name, + inf.lib.name); + // Recursively activate more libraries used by this library. + activate_more(found->second); + } + for (const auto& sibling : found->second.lib.intra_using) { + add_named(sibling); + } + if (inf.sdt.params.build_tests) { + for (const auto& sibling : found->second.lib.intra_test_using) { + add_named(sibling); + } + } + }; + add_named(use); } } }; From 572dd01d7e44f07b81bd153a7ffffb36043ded94 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 30 Apr 2022 21:30:40 -0600 Subject: [PATCH 20/62] Better error messages when specifying libraries that don't exist in packages that do --- src/bpt/cli/cmd/build_common.cpp | 27 ++++++++++++++++++----- src/bpt/cli/cmd/pkg_solve.cpp | 27 ++++++++++++++++++----- src/bpt/solve/solve.cpp | 38 +++++++++++++++++++++++++++----- src/bpt/solve/solve.hpp | 5 +++++ 4 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/bpt/cli/cmd/build_common.cpp b/src/bpt/cli/cmd/build_common.cpp index 154bcedf..0c54e4ea 100644 --- a/src/bpt/cli/cmd/build_common.cpp +++ b/src/bpt/cli/cmd/build_common.cpp @@ -101,16 +101,33 @@ crs::package_info bpt::cli::fetch_cache_load_dependency(crs::cache& cache int bpt::cli::handle_build_error(std::function fn) { return bpt_leaf_try { return fn(); } bpt_leaf_catch(e_dependency_solve_failure, - e_dependency_solve_failure_explanation explain, - const std::vector& missing_pkgs) + e_dependency_solve_failure_explanation explain, + const std::vector* missing_pkgs, + const std::vector* missing_libs) ->int { bpt_log( error, "No dependency solution is possible with the known package information: \n{}"_styled, explain.value); - for (auto& missing : missing_pkgs) { - missing.log_error( - "Direct requirement on '.bold.red[{}]' does not name an existing package in any enabled repositories"_styled); + if (missing_pkgs) { + for (auto& missing : *missing_pkgs) { + missing.log_error( + "Direct requirement on '.bold.red[{}]' does not name an existing package in any enabled repositories"_styled); + } + } + if (missing_libs) { + for (auto& lib : *missing_libs) { + bpt_log( + error, + "There is no available version of .bold.yellow[{}] that contains a library named \".bold.red[{}]\""_styled, + lib.pkg_name.str, + lib.lib.given); + if (lib.lib.nearest) { + bpt_log(error, + " (Did you mean \".bold.yellow[{}]\"?)"_styled, + *lib.lib.nearest); + } + } } write_error_marker("no-dependency-solution"); return 1; diff --git a/src/bpt/cli/cmd/pkg_solve.cpp b/src/bpt/cli/cmd/pkg_solve.cpp index 2aeb5c30..439a6835 100644 --- a/src/bpt/cli/cmd/pkg_solve.cpp +++ b/src/bpt/cli/cmd/pkg_solve.cpp @@ -40,14 +40,31 @@ static int _pkg_solve(const options& opts) { int pkg_solve(const options& opts) { return bpt_leaf_try { return _pkg_solve(opts); } bpt_leaf_catch(e_dependency_solve_failure, - e_dependency_solve_failure_explanation explain, - const std::vector& missing_pkgs) { + e_dependency_solve_failure_explanation explain, + const std::vector* missing_pkgs, + const std::vector* missing_libs) { bpt_log(error, "No solution is possible with the known package information: \n{}"_styled, explain.value); - for (auto& missing : missing_pkgs) { - missing.log_error( - "Direct requirement on '.bold.red[{}]' does not name an existing package in any enabled repositories"_styled); + if (missing_pkgs) { + for (auto& missing : *missing_pkgs) { + missing.log_error( + "Direct requirement on '.bold.red[{}]' does not name an existing package in any enabled repositories"_styled); + } + } + if (missing_libs) { + for (auto& lib : *missing_libs) { + bpt_log( + error, + "There is no available version of .bold.yellow[{}] that contains a library named \".bold.red[{}]\""_styled, + lib.pkg_name.str, + lib.lib.given); + if (lib.lib.nearest) { + bpt_log(error, + " (Did you mean \".bold.yellow[{}]\"?)"_styled, + *lib.lib.nearest); + } + } } write_error_marker("no-dependency-solution"); return 1; diff --git a/src/bpt/solve/solve.cpp b/src/bpt/solve/solve.cpp index d8a5c99a..b4efbc0e 100644 --- a/src/bpt/solve/solve.cpp +++ b/src/bpt/solve/solve.cpp @@ -312,17 +312,43 @@ generate_failure_explanation(const solve_failure_exception& exc) { void try_load_nonesuch_packages(boost::leaf::error_id error, crs::cache_db const& cache, const std::vector& reqs) { + // Find packages and libraries that aren't at all available error.load([&](std::vector& missing) { for (auto& req : reqs) { auto cands = cache.for_package(req.name); - if (cands.begin() != cands.end()) { - // This requirement has candidates + auto it = cands.begin(); + if (it == cands.end()) { + // This requirement has no candidates + auto all = cache.all_enabled(); + auto all_names = all + | stdv::transform([](auto entry) { return entry.pkg.id.name.str; }) + | neo::to_vector; + missing.emplace_back(req.name.str, did_you_mean(req.name.str, all_names)); continue; } - auto all = cache.all_enabled(); - auto all_names = all | stdv::transform([](auto entry) { return entry.pkg.id.name.str; }) - | neo::to_vector; - missing.emplace_back(req.name.str, did_you_mean(req.name.str, all_names)); + error.load([&](std::vector& missing_libs) { + auto want_libs = req.uses; + sr::sort(want_libs); + std::set all_lib_names; + for (; it != cands.end() and not want_libs.empty(); ++it) { + auto cand_has_libs = it->pkg.libraries + | stdv::transform(&crs::library_info::name) | neo::to_vector; + sr::sort(cand_has_libs); + std::vector missing_libs; + sr::set_difference(want_libs, cand_has_libs, std::back_inserter(missing_libs)); + want_libs = std::move(missing_libs); + extend(all_lib_names, cand_has_libs | stdv::transform(&bpt::name::str)); + } + if (not want_libs.empty()) { + extend(missing_libs, + want_libs | stdv::transform([&](auto&& libname) { + return e_nonesuch_using_library{ + req.name, + e_nonesuch{libname.str, + did_you_mean(libname.str, all_lib_names)}}; + })); + } + }); } }); } diff --git a/src/bpt/solve/solve.hpp b/src/bpt/solve/solve.hpp index b835c511..fc898d20 100644 --- a/src/bpt/solve/solve.hpp +++ b/src/bpt/solve/solve.hpp @@ -28,6 +28,11 @@ struct e_nonesuch_package : e_nonesuch { using e_nonesuch::e_nonesuch; }; +struct e_nonesuch_using_library { + bpt::name pkg_name; + e_nonesuch lib; +}; + std::vector solve(crs::cache_db const&, neo::any_input_range); } // namespace bpt From 4f18255d5db8d23697dd26f034a82b418504abef Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 7 May 2022 16:45:53 -0600 Subject: [PATCH 21/62] Formatting --- src/bpt/cli/options.cpp | 21 ++++++++++----------- src/debate/argument.hpp | 3 +-- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 4b8ad5ee..2f70fa98 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -141,11 +141,10 @@ struct setup { parser.add_argument({ .long_spellings = {"log-level"}, .short_spellings = {"l"}, - .help = "" - "Set the bpt logging level. One of 'trace', 'debug', 'info', \n" - "'warn', 'error', 'critical', or 'silent'", - .valname = "", - .action = put_into(opts.log_level), + .help = "Set the bpt logging level. One of 'trace', 'debug', 'info', \n" + "'warn', 'error', 'critical', or 'silent'", + .valname = "", + .action = put_into(opts.log_level), }); parser.add_argument({ .long_spellings = {"crs-cache-dir"}, @@ -406,9 +405,9 @@ struct setup { void setup_install_yourself_cmd(argument_parser& install_yourself_cmd) { install_yourself_cmd.add_argument({ .long_spellings = {"where"}, - .help = "The scope of the installation. For .bold[system], installs in a global \n" - "directory for all users of the system. For .bold[user], installs in a \n" - "user-specific directory for executable binaries."_styled, + .help = "The scope of the installation. For .bold[system], installs in a global \n" + "directory for all users of the system. For .bold[user], installs in a \n" + "user-specific directory for executable binaries."_styled, .valname = "{user,system}", .action = put_into(opts.install_yourself.where), }); @@ -427,9 +426,9 @@ struct setup { }); install_yourself_cmd.add_argument({ .long_spellings = {"symlink"}, - .help = "Create a symlink at the installed location to the existing 'bpt' executable\n" - "instead of copying the executable file", - .nargs = 0, + .help = "Create a symlink at the installed location to the existing 'bpt' executable\n" + "instead of copying the executable file", + .nargs = 0, .action = store_true(opts.install_yourself.symlink), }); } diff --git a/src/debate/argument.hpp b/src/debate/argument.hpp index 966f8502..f72c54c5 100644 --- a/src/debate/argument.hpp +++ b/src/debate/argument.hpp @@ -88,8 +88,7 @@ constexpr inline auto parse_bool_into = [](auto& dest) { }; }; -constexpr inline auto put_into - = [](auto& dest) { return make_argument_putter(dest); }; +constexpr inline auto put_into = [](auto& dest) { return make_argument_putter(dest); }; constexpr inline auto push_back_onto = [](auto& dest) { return [&dest](std::string_view value, std::string_view = {}) { dest.emplace_back(value); }; From 24892cb53614eafcdb247f0087cc7c0c0d367cfb Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 7 May 2022 18:26:02 -0600 Subject: [PATCH 22/62] Logging for file and pkg removal, no zero pkg revision --- src/bpt/cli/cmd/repo_remove.cpp | 6 ++++-- src/bpt/crs/repo.cpp | 4 ++-- src/bpt/util/fs/shutil.cpp | 14 ++++++++++++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/bpt/cli/cmd/repo_remove.cpp b/src/bpt/cli/cmd/repo_remove.cpp index 04eb26ab..98da21f1 100644 --- a/src/bpt/cli/cmd/repo_remove.cpp +++ b/src/bpt/cli/cmd/repo_remove.cpp @@ -5,22 +5,24 @@ #include #include +#include #include #include #include +using namespace fansi::styled_literals; + namespace bpt::cli::cmd { int repo_remove(const options& opts) { auto repo = bpt::crs::repository::open_existing(opts.repo.repo_dir); for (auto pkg : opts.repo.remove.pkgs) { auto pkg_id = bpt::crs::pkg_id::parse(pkg); + bpt_log(info, "Removing .bold.yellow[{}]"_styled, pkg_id.to_string()); /// We only need the name and version info to do the removal bpt::crs::package_info meta; meta.id = pkg_id; - // Zero to remove all package revisions - meta.id.revision = 0; repo.remove_pkg(meta); } return 0; diff --git a/src/bpt/crs/repo.cpp b/src/bpt/crs/repo.cpp index 1d72e37b..8f20d66c 100644 --- a/src/bpt/crs/repo.cpp +++ b/src/bpt/crs/repo.cpp @@ -192,12 +192,12 @@ void repository::remove_pkg(const package_info& meta) { DELETE FROM crs_repo_packages WHERE name = ?1 AND version = ?2 - AND (pkg_version = ?3 - OR ?3 = 0) + AND (pkg_version = ?3) )"_sql), meta.id.name.str, meta.id.version.to_string(), meta.id.revision) .value(); + bpt_log(debug, "Deleting subdirectory [{}]", to_delete.string()); ensure_absent(to_delete).value(); } diff --git a/src/bpt/util/fs/shutil.cpp b/src/bpt/util/fs/shutil.cpp index 55864fcc..88b0a244 100644 --- a/src/bpt/util/fs/shutil.cpp +++ b/src/bpt/util/fs/shutil.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -16,9 +17,18 @@ using namespace bpt; result bpt::ensure_absent(path_ref path) noexcept { BPT_E_SCOPE(e_remove_file{path}); std::error_code ec; + bpt_log(trace, "Recursive ensure-absent [{}]", path.string()); fs::remove_all(path, ec); - if (ec && ec != std::errc::no_such_file_or_directory) { - return new_error(ec); + if (ec) { + const bool is_enoent = ec == std::errc::no_such_file_or_directory; + bpt_log(trace, + " Ensure-absent error while removing [{}]: {}{}", + path.string(), + ec.message(), + is_enoent ? " (Ignoring this error)" : ""); + if (not is_enoent) { + return new_error(ec); + } } return {}; } From fff743b3849f1af5e43b72d6cd12e1b8ee389cbd Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 7 May 2022 18:26:28 -0600 Subject: [PATCH 23/62] No generated tables. They're bloaty and unused. --- src/bpt/crs/cache_db.cpp | 53 +++++----------------------------------- 1 file changed, 6 insertions(+), 47 deletions(-) diff --git a/src/bpt/crs/cache_db.cpp b/src/bpt/crs/cache_db.cpp index 5fd672ee..23817300 100644 --- a/src/bpt/crs/cache_db.cpp +++ b/src/bpt/crs/cache_db.cpp @@ -87,48 +87,6 @@ cache_db cache_db::open(unique_database& db) { STORED, UNIQUE (name, version, pkg_version, remote_id) ); - - CREATE TABLE bpt_crs_libraries ( - lib_id INTEGER PRIMARY KEY, - pkg_id INTEGER NOT NULL - REFERENCES bpt_crs_packages - ON DELETE CASCADE, - name TEXT NOT NULL, - path TEXT NOT NULL, - UNIQUE (pkg_id, name) - ); - - CREATE TRIGGER bpt_crs_libraries_auto_insert - AFTER INSERT ON bpt_crs_packages - FOR EACH ROW - BEGIN - INSERT INTO bpt_crs_libraries (pkg_id, name, path) - WITH libraries AS ( - SELECT value FROM json_each(new.json, '$.libraries') - ) - SELECT - new.pkg_id, - json_extract(lib.value, '$.name'), - json_extract(lib.value, '$.path') - FROM libraries AS lib; - END; - - CREATE TRIGGER bpt_crs_libraries_auto_update - AFTER UPDATE ON bpt_crs_packages - FOR EACH ROW WHEN new.json != old.json - BEGIN - DELETE FROM bpt_crs_libraries - WHERE pkg_id = new.pkg_id; - INSERT INTO bpt_crs_libraries (pkg_id, name, path) - WITH libraries AS ( - SELECT value FROM json_each(new.json, '$.libraries') - ) - SELECT - new.pkg_id, - json_extract(lib.value, '$.name'), - json_extract(lib.value, '$.path') - FROM libraries AS lib; - END; )"_sql); }).value(); db.exec_script(R"( @@ -327,11 +285,12 @@ neo::co_resource get_remote_db(bpt::unique_database& db, ne co_yield info; } else { bpt::http_request_params params; - auto& prio_info_st = db.prepare( - "SELECT etag, last_modified, resource_time, cache_control " - "FROM bpt_crs_remotes " - "WHERE url=?"_sql); - auto url_str = url.to_string(); + // Open the prior download info from the cachedb + auto& prio_info_st = db.prepare(R"( + SELECT etag, last_modified, resource_time, cache_control + FROM bpt_crs_remotes + WHERE url=?)"_sql); + auto url_str = url.to_string(); neo_assertion_breadcrumbs("Pulling remote repository metadata", url_str); bpt_log(debug, "Syncing repository [{}] via HTTP", url_str); neo::sqlite3::reset_and_bind(prio_info_st, std::string_view(url_str)).throw_if_error(); From e9b77ab0455abc8c2fb9bf98d7977284a9c350c8 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 7 May 2022 18:26:38 -0600 Subject: [PATCH 24/62] Update the default repository. --- src/bpt/cli/cmd/cache_util.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bpt/cli/cmd/cache_util.cpp b/src/bpt/cli/cmd/cache_util.cpp index 771c7c84..531a6cd6 100644 --- a/src/bpt/cli/cmd/cache_util.cpp +++ b/src/bpt/cli/cmd/cache_util.cpp @@ -147,7 +147,7 @@ crs::cache cli::open_ready_cache(const cli::options& opts) { use_repo(meta_db, opts, r); } if (opts.use_default_repo) { - use_repo(meta_db, opts, "repo-2.dds.pizza"); + use_repo(meta_db, opts, "repo-3.bpt.pizza"); } return cache; } From b09ef8ea1292bf40baa4302ef3a2aed614233d0e Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 7 May 2022 18:32:12 -0600 Subject: [PATCH 25/62] No formatting check (for now) --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 491fffcf..28f8f315 100644 --- a/Makefile +++ b/Makefile @@ -46,7 +46,7 @@ _alpine-static-ci: -o test-toolchain=tools/gcc-10-static-rel.jsonc \ --interface simple \ --fail-cancels \ - test format.check + test poetry run dagon \ -o main-toolchain=tools/gcc-10-static-rel.jsonc \ --interface simple \ From 5a97f63bc543194504df6193da60b118fbf2527d Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 11 May 2022 21:38:55 -0600 Subject: [PATCH 26/62] More doc updates --- docs/conf.py | 31 +-- docs/crs/index.rst | 14 +- docs/design.rst | 2 +- docs/err/invalid-pkg-filesystem.rst | 2 +- docs/err/invalid-pkg-ident.rst | 4 +- docs/guide/deps.rst | 329 ++++++++++++++++++++++++++++ docs/guide/index.rst | 6 +- docs/guide/interdeps.rst | 246 --------------------- docs/guide/libraries.rst | 196 ++++++++++++++++- docs/guide/packages.rst | 208 ------------------ docs/guide/projects.rst | 232 ++++++++++++++++++++ docs/guide/remote-pkgs.rst | 196 +++++------------ docs/guide/terms.rst | 57 ++++- docs/guide/toolchains.rst | 155 +++++++------ docs/howto/deps.rst | 4 +- docs/prolog.rst | 33 +++ 16 files changed, 992 insertions(+), 723 deletions(-) create mode 100644 docs/guide/deps.rst delete mode 100644 docs/guide/interdeps.rst delete mode 100644 docs/guide/packages.rst create mode 100644 docs/guide/projects.rst create mode 100644 docs/prolog.rst diff --git a/docs/conf.py b/docs/conf.py index dc7122de..e76972fc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -2,6 +2,7 @@ # Refer: http://www.sphinx-doc.org/en/master/config from sphinx.application import Sphinx + from pathlib import Path from typing import Any import sys @@ -29,7 +30,7 @@ source_suffix = '.rst' master_doc = 'index' language = None -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'prolog.rst'] pygments_style = None intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), @@ -72,33 +73,7 @@ def intercept_copy_asset(path: str, dest: str, context: Any) -> None: hoverxref.extension.copy_asset = intercept_copy_asset rst_prolog = r''' -.. role:: bpt-name(literal) - :class: bpt-name - -.. |bpt| replace:: :bpt-name:`bpt` - -.. |code-open| raw:: html - - - -.. |code-close| raw:: html - - - -.. |bpt.yaml| replace:: |code-open|\ :term:`bpt.yaml`\ |code-close| - -.. |crs.json| replace:: |code-open|\ :ref:`crs.json`\ |code-close| - -.. role:: yaml(code) - :language: yaml - :class: highlight - -.. role:: cpp(code) - :language: cpp - :class: highlight - -.. |#include| replace:: :cpp:`#include` - +.. include:: /prolog.rst ''' diff --git a/docs/crs/index.rst b/docs/crs/index.rst index 9bfbe3db..9106643c 100644 --- a/docs/crs/index.rst +++ b/docs/crs/index.rst @@ -85,23 +85,23 @@ disk, a Zip archive, a Tar archive, a database table, or even something as simple as a single large `JSON` document. -.. _crs.json: +.. _pkg.json: -``crs.json`` +``pkg.json`` ************ -At the root of the package must be a valid `JSON` document named ``crs.json``. +At the root of the package must be a valid `JSON` document named ``pkg.json``. This file encodes all of the metadata in the package. At any point in the `JSON` object, if any `JSON` object key string begins with the substring "``_comment``", then content of that object entry is to be ignored for validating the `JSON` data. -The basic interface of ``crs.json`` looks as below: +The basic interface of ``pkg.json`` looks as below: .. code-block:: javascript - interface CRSJSON { + interface PKGJSON { "schema-version": 1, name: NameString, version: VersionString, @@ -193,8 +193,8 @@ attributes for the package. Libraries ********* -In :ref:`crs.json`, the ``libraries`` property must be an array of CRS library -JSON objects. +In |pkg.json|, the ``libraries`` property must be an array of CRS library JSON +objects. Each object in that array defines a library for the package. Each object must contain the following properties: diff --git a/docs/design.rst b/docs/design.rst index ef957239..92878514 100644 --- a/docs/design.rst +++ b/docs/design.rst @@ -142,7 +142,7 @@ structure layout with minimal differing options. |bpt| prescribes the .. note:: These prescriptions are not as draconian as they may sound upon first - reading. Refer to the :doc:`guide/packages` page for more information. + reading. Refer to the :doc:`guide/projects` page for more information. .. _Pitchfork: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs diff --git a/docs/err/invalid-pkg-filesystem.rst b/docs/err/invalid-pkg-filesystem.rst index 6c8d9dc5..b4109a84 100644 --- a/docs/err/invalid-pkg-filesystem.rst +++ b/docs/err/invalid-pkg-filesystem.rst @@ -3,7 +3,7 @@ Error: Invalid package filesystem |bpt| prescribes a filesystem structure that must be followed for it to build and process packages and libraries. This structure isn't overly strict, -and is thoroughly explained on the :doc:`/guide/packages` page. +and is thoroughly explained on the :doc:`/guide/projects` page. For exporting/generating a source distribution from a package, the *package root* requires a ``package.json5`` file and each *library root* requires a diff --git a/docs/err/invalid-pkg-ident.rst b/docs/err/invalid-pkg-ident.rst index 165d970a..17371020 100644 --- a/docs/err/invalid-pkg-ident.rst +++ b/docs/err/invalid-pkg-ident.rst @@ -7,5 +7,5 @@ Package identifiers in |bpt| must follow a well-defined pattern of .. seealso:: - - :doc:`/guide/packages` - - :doc:`/crs/names`. + - :doc:`/guide/projects` + - :doc:`/crs/names`. diff --git a/docs/guide/deps.rst b/docs/guide/deps.rst new file mode 100644 index 00000000..4b439662 --- /dev/null +++ b/docs/guide/deps.rst @@ -0,0 +1,329 @@ +##################### +Dependencies in |bpt| +##################### + +.. default-role:: term +.. highlight:: yaml + +In |bpt| a `project` or `library` can declare dependencies on +`libraries ` in external `packages `. A dependency consists of +an external package `name`, a range of acceptable :ref:`versions `, and +some set of libraries to *use* from that external package. + +Dependencies can be set using the :yaml:`dependencies` property on either the +top-level of |bpt.yaml|, or as a property attached to an invidual library within +the project. The similar :yaml:`test-dependencies` key specifies dependencies +that are required to build and execute the project's `tests `. + +These dependency properties should be an array of +*dependency specifiers*. + +.. _dep-spec: + +Dependency Specifiers +##################### + +The :yaml:`dependencies` and :yaml:`test-dependencies` arrays in |bpt.yaml| are +used to declare `dependencies ` on libraries in external packages:: + + dependencies: + - dep-name@1.2.3 + +The above specifier requests a package named "``dep-name``" with a version range +of greater-or-equal-to-``1.2.3`` and less-than ``2.0.0``, and uses the +`default library` from that project (The library with the same name as the +package itself). + +If a package provides more than one library, or does not use a +`default library`, the dependency specifier can include a :cpp:`using` clause to +name one or more comma-separated library names to use from the package:: + + dependencies: + - acme@1.2.3 using widgets, gadgets + +If the :cpp:`using` clause is omitted an implicit ":cpp:`using [pkg-name]`" is +assumed, with ``[pkg-name]`` being the name of the depended-on package. + +More formally: A dependency specifier (:token:`dep-spec`) is a string of the +following format: + +.. productionlist:: + dep-spec: `dep_name` `dep_range` ["using" `lib_name` ("," `lib_name`)+] + dep_name: name + lib_name: name + dep_range: `range_sym` dep_version + range_sym: "@" | "^" | "~" | "=" | "+" + dep_version: version + +alternatively:: + + {@,^,~,=,+} [using [, [...]]] + +- The :token:`dep_name` must be the `name` of an external package. +- The :token:`dep_version` must be a valid + :ref:`Semantic Version number `. +- The choice of the :token:`range_sym` symbol alters the semantics of the + version range. Refer: :ref:`deps.ranges` +- If :cpp:`using` is provided, the :token:`lib_name` tokens must be the names of + one or more libraries within the external package that are to be used. The + :cpp:`using` suffix may be omitted. + + +.. _deps.ranges: + +Compatible Range Specifiers +*************************** + +When specifying a dependency on a package, one will want to specify which +versions of the dependency are supported. + +.. note:: + + Unlike other packaging tools, |bpt| will find a solution with the *lowest* + possible version that satisfies the given requirements for each package. + This decision is not incidental: It's entirely intentional. Refer to: + :ref:`deps.ranges.why-lowest`. + +|bpt| compatible-version ranges use similar syntax to other tools. There are +four version range kinds available, listed in order of most-to-least +restrictive: + +Exact: ``=1.2.3`` + Specifies an *exact* requirement. The dependency must match the named + version *exactly* or it is considered incompatible. + +Minor: ``~1.2.3`` + Specifies a *minor* requirement. The version of the dependency should be + *at least* the given version, but not as new or newer than the next minor + revision. In this example, it represents the half-open version range + ``[1.2.3, 1.3.0)``. + +Major: ``^1.2.3`` or ``@1.2.3`` + Specifies a *major* requirement. The version must be *at least* the same + given version, but not any newer than the the next major version. In the + example, this is the half-open range ``[1.2.3, 2.0.0)``. + + .. note:: + This is the recommended default option to reach for, as it matches the + intended behavior of `Semantic Versioning `_. + +At-least: ``+1.2.3`` + Specifies an *at least* requirement. The version must be *at least* the + given version, but any newer version is acceptable. + + +.. _deps.ranges.why-lowest: + +Why Pull the *Lowest* Matching Version? +####################################### + +When resolving dependencies, |bpt| will pull the version of the dependency +that is the lowest version that satisfies the given range. In most cases, +this will be the same version that is the base of the version range. + +Imagine a scenario where we *did* select the "latest-matching-version": + +Suppose we are developing a library ``Gadgets``, and we wish to make use of +``Widgets``. The latest version is ``1.5.2``, and they promise Semantic +Versioning compatibility, so we select a dependency statement of +``Widgets^1.5.2``. + +Suppose a month passes, and ``Widgets@1.6.0`` is published. A few things +happen: + +#. Our CI builds now switch from ``1.5.2`` to ``1.6.0`` *without any code + changes*. Should be okay, right? I mean... it's still compatible, yeah? +#. Bugs in ``Widgets@1.6.0`` will now appear in all CI builds, and won't be + reproducible locally unless we re-pull our dependencies and obtain the + new version of ``Widgets``. This requires that we be conscientious enough to + realize what is actually going on. +#. Even if ``Widgets@1.6.0`` introduces no new bugs, a developer re-pulling + their dependencies will suddenly be developing against ``1.6.0``, and may + not even realize it. In fact, this may continue for weeks or months until + *everyone* is developing against ``1.6.0`` without realizing that they + actually only require ``1.5.2`` in their dependency declarations. +#. Code in our project is written that presupposes features or bugfixes added + in ``1.6.0``, and thus makes the dependency declaration on ``Widgets^1.5.2`` + a *lie*. + +Pulling the lowest-matching-version has two *huge* benefits: + +#. No automatic CI upgrades. The code built today will produce the same result + when built a year from now. +#. Using a feature/fix beyond our minimum requirement becomes a compile error, + and we catch these up-front rather than waiting for a downstream user + discovering them for us. + + +.. rubric:: *Isn't this what lockfiles are for?* + +Somewhat. Lockfiles will prevent automatic upgrades, but they will do nothing +to stop accidental reliance on new versions. There are other useful features +of lockfiles, but preventing automatic upgrades can be a non-issue by simply +using lowest-matching-version. + + +.. rubric:: *So, if this is the case, why use ranges at all?* + +In short: *Your* compatibility ranges are not for *you*. They are for *your +users*. + +Suppose package ``A`` requires ``B^1.0.0``, and ``B`` requires ``C^1.2.0``. +Now let us suppose that ``A`` wishes to use a newer feature of ``C``, and thus +declares a dependency on ``C^1.3.0``. ``B`` and ``A`` have different +compatibility ranges on ``C``, but this will work perfectly fine **as long as +the compatible version ranges of A and B have some overlap**. + +That final qualification is the reason we use compatibility ranges: To support +our downstream users to form dependency graphs that would otherwise form +conflicts if we required *exact* versions for everything. In the above example, +``C@1.3.0`` will be selected for the build of ``A``. + +Now, if another downstream user wants to use ``A``, they will get ``C@1.3.0``. +But they discover that they actually need a bugfix in ``C``, so they place +their own requirement on ``C ^1.3.1``. Thus, they get ``C@1.3.1``, which still +satisfies the compatibility ranges of ``A`` and ``B``. Everyone gets along +just fine! + + +Dependency Compatibility and the :cpp:`using` Specifier +####################################################### + +Besides requiring that a candidate for dependency resolution meet the version +requirements, the candidate must also provide all of the libraries named by the +:cpp:`using` specifier on the dependency statement. + +.. default-role:: math + +A Simple Example +**************** + +For example, suppose that the following packages are available: + +- ``acme-libs@1.2.0`` - Provides one library: ``widgets``. +- ``acme-libs@1.3.0`` - Provides libraries ``widgets`` and ``gadgets``. +- ``acme-libs@1.4.0`` - Provides libraries ``gadgets``, and + ``gizmos`` + +Suppose now I have a project |bpt.yaml|: + +.. code-block:: yaml + + name: my-code + version: 4.2.4 + + dependencies: + - acme-libs@1.0.0 using gadgets, widgets + +Our package contains a single dependency statement `R_1` of +``acme-libs@1.0.0 using gadgets, widgets``. When |bpt| does dependency +resolution, it sees the requirement on ``acme-libs`` and seeks out a compatilbe +version. Since |bpt| prefers to find the *lowest-matching-version*, it begins by +considering ``acme-libs@1.2.0``. Good news: This matches the *version* +requirement of `R_1`! Bad news: Our dependency `R_1` has a +:cpp:`using gadgets, widgets`, and the ``1.2.0`` version of ``acme-libs`` does +not provide the required ``gadgets`` library. + +|bpt| will mark ``acme-libs@1.2.0`` as *incompatible* with `R_1` and move on to +the next candidate: ``acme-libs@1.3.0``. Great news: This version both matches +the version requirement `R_1` *and* provides *both* libraries required by `R_1`. +Thus, ``acme-libs@1.3.0`` will be selected to solve `R_1`. + +Since `R_1` is the only dependency statement, we have a complete dependency +solution with just selecting ``acme-libs@1.3.0``. + + +Getting More Complicated +************************ + +Suppose now that there are additional packages available for use: + +- ``gandalf@6.3.0`` + + - Provides library ``wizard`` which depends on + ``acme-libs@1.2.0 using gizmos``. + +- ``gandalf@6.4.0`` + + - Provides ``wizard``, which depends on ``acme-libs@1.2.0 using gadgets`` + +Let's update our |bpt.yaml| to use this package: + +.. code-block:: yaml + + name: my-code + version: 4.3.0 + + dependencies: + - acme-libs@1.0.0 using gadgets, widgets + - gandalf@6.0.0 using wizard + +In addition to our previous dependency `R_1` of +``acme-libs@1.0.0 using gadgets, widgets``, we now have an additional +requirement `R_2` of ``gadgalf@6.0.0 using wizard``. Dependency resolution now +becomes more complex: + +1. In solving `R_2`, we first check ``gandalf@6.3.0`` + + 1. This looks okay at first: This package matches our version requirement in + `R_2` *and* it also provides the ``wizard`` library that we are + :cpp:`using` in `R_2`. + + 2. |bpt| will speculatively select this package as part of the solution. + +2. |bpt| will now validate the new package against the "partial solution" that + we are working with. + +3. The used ``wizard`` library of the selected ``gandalf@6.3.0`` has its own + dependency `R_g1` of ``acme-libs@1.2.0 using gizmos``. We can take the + *intersection* `R_x = R_1 \cap R_g1` of our existing requirement `R_1` on + ``acme-libs`` to form a new *derived* requirement `R_x =` + ``acme-libs@1.0.0 using gadgets, widgets, gizmos`` + + This `R_x` is the dependency *intersection* of `R_g1` and `R_1` because any + selection that satisfies `R_x` will necessarily also satisfy `R_g1` and + `R_1`. + +4. |bpt| must now seek a version of ``acme-libs`` that satisfies `R_x`, but a + cursory glance reveals that `R_x` is *unsatisfiable*: There is no + ``acme-libs`` package that provides ``gadgets`` *and* ``widgets`` *and* + ``gizmos``. (|bpt| encodes this fact with a special requirement + ``acme-libs@[⊥]``, which is unsatisfiable *by definition*. This notation may + appear in diagnostics during dependency resolution failure.) + +5. Because our partial solution contains an unsatisfiable derived requirement, + the entire partial solution is invalid, and |bpt| must backtrack to find the + speculative decision that caused the failure. In this case, the speculative + selection of ``gandalf@6.3.0`` caused the creation of an unsatisfiable + partial solution, so we transitively mark ``gandalf@6.3.0`` as *incompatible* + with the partial solution that led to its selection. + +6. With ``gandalf@6.3.0`` ruled out, we need to find another package to satisfy + `R_2`. Fortunately, we have one: ``gandalf@6.4.0``. This is speculatively + selected for the solution. + +7. The ``gandalf@6.4.0`` library ``wizard`` contains a new requirement `R_g2` of + ``acme-libs@1.2.0 using gadgets``, which we will check against our existing + partial solution. + +8. The speculated selection of ``acme-libs@1.3.0`` satisfies ``R_g2``, so the + partial solution is okay. + +9. There are no remaining unsatisfied requirements, so we select + ``acme-libs@1.3.0`` and ``gandalf@6.4.0`` as our dependency solution. + + +A Note on Library *Removal* +*************************** + +In the above example, the ``acme-libs@1.4.0`` simltaneously *added* the +``gizmos`` library and *removed* the ``widgets`` library. + +The removal of a library from a package is necessarily a breaking change, and is +especially troublesome here in that there is no version of the package that +contains all of ``widgets``, ``gadgets``, and ``gizmos``. Any dependency +statement (derived or direct) that requests all three libraries will be +unsatisfiable. It is very highly recommended to refrain from removing libraries +as part of a minor version change, thus reducing the likelihood of such +conflicts. + diff --git a/docs/guide/index.rst b/docs/guide/index.rst index d74dbbae..8bfd924e 100644 --- a/docs/guide/index.rst +++ b/docs/guide/index.rst @@ -4,14 +4,14 @@ User Guide .. toctree:: :maxdepth: 2 - cli/index - packages + projects libraries apps tests + deps + cli/index toolchains remote-pkgs - interdeps build-deps cmake diff --git a/docs/guide/interdeps.rst b/docs/guide/interdeps.rst deleted file mode 100644 index b339ea57..00000000 --- a/docs/guide/interdeps.rst +++ /dev/null @@ -1,246 +0,0 @@ -.. highlight:: yaml - -Library and Package Dependencies -################################ - -|bpt| considers that all libraries belong to a single *package*, but a single -package may contain one or more *libraries*. For this reason, and to better -interoperate with other build and packaging tools, we consider the issues of -package dependencies and library dependencies separately. - - -.. _deps.pkg-deps: - -Package Dependencies -******************** - -Consider that we are creating a package ``acme-gadgets@4.3.6``. We declare the -name and version in the ``package.json5`` in the package root: - -.. code-block:: js - - { - name: 'acme-gadgets', - version: '4.3.6', - namespace: 'acme', - } - -.. note:: - The ``namespace`` field is required, but will be addressed in the - :ref:`deps.lib-deps` section. - -Suppose that our package's libraries build upon the libraries in the -``acme-widgets`` package, and that we require version ``1.4.3`` or newer, but -not as new as ``2.0.0``. Such a dependency can be declared with the ``depends`` -array: - -.. code-block:: js - :emphasize-lines: 5-7 - - { - name: 'acme-gadgets', - version: '4.3.6', - namespace: 'acme', - depends: [ - 'acme-widgets^1.4.3', - ], - } - -.. seealso:: :ref:`deps.ranges`. - -If we wish to declare additional dependencies, we simply declare them with -additional ``depends`` items: - -.. code-block:: - :emphasize-lines: 7-8 - - { - name: 'acme-gadgets', - version: '4.3.6', - namespace: 'acme', - depends: [ - 'acme-widgets^1.4.3', - 'acme-gizmos~5.6.5', - 'acme-utils^3.3.0', - ], - } - -When |bpt| attempts to build a project, it will first build the dependency -solution by iteratively scanning the dependencies of the containing project and -all transitive dependencies. - - -.. _deps.ranges: - -Compatible Range Specifiers -=========================== - -When specifying a dependency on a package, one will want to specify which -versions of the dependency are supported. - -.. note:: - Unlike other packaging tools, |bpt| will find a solution with the - *lowest* possible version that satisfies the given requirements for each - package. This decision is not incidental: It's entirely intentional. - Refer to: :ref:`deps.ranges.why-lowest`. - -|bpt| compatible-version ranges are similar to the shorthand range specifiers -supported by ``npm`` and ``npm``-like tools. There are four version range kinds -available, listed in order of most-to-least restrictive: - -Exact: ``@1.2.3`` - Specifies an *exact* requirement. The dependency must match the named - version *exactly* or it is considered incompatible. - -Minor: ``~1.2.3`` - Specifies a *minor* requirement. The version of the dependency should be - *at least* the given version, but not as new or newer than the next minor - revision. In this example, it represents the half-open version range - ``[1.2.3, 1.3.0)``. - -Major: ``^1.2.3`` - Specifies a *major* requirement. The version must be *at least* the same - given version, but not any newer than the the next major version. In the - example, this is the half-open range ``[1.2.3, 2.0.0)``. - - .. note:: - This is the recommended default option to reach for, as it matches the - intended behavior of `Semantic Versioning `_. - -At-least: ``+1.2.3`` - Specifies an *at least* requirement. The version must be *at least* the - given version, but any newer version is acceptable. - -A dependency string is simply the name of the package with the range suffix appended. - - -.. _deps.ranges.why-lowest: - -Why Pull the *Lowest* Matching Version? ---------------------------------------- - -When resolving dependencies, |bpt| will pull the version of the dependency -that is the lowest version that satisfies the given range. In most cases, -this will be the same version that is the base of the version range. - -Imagine a scenario where we *did* select the "latest-matching-version": - -Suppose we are developing a library ``Gadgets``, and we wish to make use of -``Widgets``. The latest version is ``1.5.2``, and they promise Semantic -Versioning compatibility, so we select a dependency statement of -``Widgets^1.5.2``. - -Suppose a month passes, and ``Widgets@1.6.0`` is published. A few things -happen: - -#. Our CI builds now switch from ``1.5.2`` to ``1.6.0`` *without any code - changes*. Should be okay, right? I mean... it's still compatible, yeah? -#. Bugs in ``Widgets@1.6.0`` will now appear in all CI builds, and won't be - reproducible locally unless we re-pull our dependencies and obtain the - new version of ``Widgets``. This requires that we be conscientious enough to - realize what is actually going on. -#. Even if ``Widgets@1.6.0`` introduces no new bugs, a developer re-pulling - their dependencies will suddenly be developing against ``1.6.0``, and may - not even realize it. In fact, this may continue for weeks or months until - *everyone* is developing against ``1.6.0`` without realizing that they - actually only require ``1.5.2`` in their dependency declarations. -#. Code in our project is written that presupposes features or bugfixes added - in ``1.6.0``, and thus makes the dependency declaration on ``Widgets^1.5.2`` - a *lie*. - -Pulling the lowest-matching-version has two *huge* benefits: - -#. No automatic CI upgrades. The code built today will produce the same result - when built a year from now. -#. Using a feature/fix beyond our minimum requirement becomes a compile error, - and we catch these up-front rather than waiting for a downstream user - discovering them for us. - - -*Isn't this what lockfiles are for?* -"""""""""""""""""""""""""""""""""""" - -Somewhat. Lockfiles will prevent automatic upgrades, but they will do nothing -to stop accidental reliance on new versions. There are other useful features -of lockfiles, but preventing automatic upgrades can be a non-issue by simply -using lowest-matching-version. - - -*So, if this is the case, why use ranges at all?* -""""""""""""""""""""""""""""""""""""""""""""""""" - -In short: *Your* compatibility ranges are not for *you*. They are for *your -users*. - -Suppose package ``A`` requires ``B^1.0.0``, and ``B`` requires ``C^1.2.0``. -Now let us suppose that ``A`` wishes to use a newer feature of ``C``, and thus -declares a dependency on ``C^1.3.0``. ``B`` and ``A`` have different -compatibility ranges on ``C``, but this will work perfectly fine **as long as -the compatible version ranges of A and B have some overlap**. - -That final qualification is the reason we use compatibility ranges: To support -our downstream users to form dependency graphs that would otherwise form -conflicts if we required *exact* versions for everything. In the above example, -``C@1.3.0`` will be selected for the build of ``A``. - -Now, if another downstream user wants to use ``A``, they will get ``C@1.3.0``. -But they discover that they actually need a bugfix in ``C``, so they place -their own requirement on ``C ^1.3.1``. Thus, they get ``C@1.3.1``, which still -satisfies the compatibility ranges of ``A`` and ``B``. Everyone gets along -just fine! - - -.. _deps.lib-deps: - -Library Dependencies -******************** - -In |bpt|, library interdependencies are tracked separately from the packages -that contain them. A library must declare its intent to use another library -in the ``library.json5`` at its library root. The minimal content of a -``library.json5`` is the ``name`` key: - -.. code-block:: js - - { - name: 'gadgets' - } - -To announce that a library wishes to *use* another library, use the aptly-named -``uses`` key: - -.. code-block:: js - :emphasize-lines: 3-7 - - { - name: 'gadgets', - uses: [ - 'acme/widgets', - 'acme/gizmos', - 'acme/utils', - ], - } - -Here is where the package's ``namespace`` key comes into play: A library's -qualified name is specified by joining the ``namespace`` of the containing -package with the ``name`` of the library within that package with a ``/`` -between them. - -It is the responsibility of package authors to document the ``namespace`` and -``name`` of the packages and libraries that they distribute. - -.. note:: - The ``namespace`` of a package is completely arbitrary, and need not relate - to a C++ ``namespace``. - -.. note:: - The ``namespace`` need not be unique to a single package. For example, a - single organization (Like Acme Inc.) can share a single ``namespace`` for - many of their packages and libraries. - - However, it is essential that the ``/`` pair be - universally unique, so choose wisely! - -Once the ``uses`` key appears in the ``library.bpt`` file of a library, |bpt| -will make available the headers for the library being used, and will -transitively propagate that usage requirement to users of the library. diff --git a/docs/guide/libraries.rst b/docs/guide/libraries.rst index ebc35f4b..093c9c5f 100644 --- a/docs/guide/libraries.rst +++ b/docs/guide/libraries.rst @@ -4,11 +4,11 @@ Libraries in |bpt| .. default-role:: term In |bpt|, all code belongs to a `library`, and every library belongs by either a -|bpt| `project` or a `package`. A library can `depend on ` other -libraries within the same project/package and on libraries in external packages. +|bpt| `project` or a `package`. -Every library in |bpt| has a `name`, and that name must be unique within the -`package` that owns it. +By default, a |bpt| project only has a single `default library`. A project can +be subdivided into more libraries by using the :yaml:`libraries` property. A +library can `depend on ` other libraries in external packages. |bpt| uses the filesystem layout of the library to derive information about it. Every library has a `library root` directory. A library root contains either @@ -23,10 +23,12 @@ The project's |bpt.yaml| defines the `library roots ` of every library in the project: - If relying on the `default library`, the `library root` is the same as the - `project root` of the project that contains it. + `project root` of the project that contains it. This is the recommended usage + mode for most projects. - If using :ref:`explicitly declared libraries `, the `library root` is defined by a relative path specified using the :yaml:`path` - property of the library declaration in |bpt.yaml|. + property of the library declaration in |bpt.yaml| (Refer: + :ref:`proj.lib-properties`). Every library root must contain a ``src/`` directory, *or* an ``include/`` directory, *or both*. |bpt| will treat both directories as @@ -40,6 +42,76 @@ generate an archive to be included in downstream binaries, but it will still generate link rules for the dependencies of a header-only library. +.. _guide.default-library: + +The Default Library +******************* + +In |bpt|, all code belongs to a `library`. If a |bpt.yaml| file omits the +:yaml:`libraries` property, |bpt| will assume that the `project`'s +`default library` lives in the same directory as |bpt.yaml| and has a library +:yaml:`name` equivalent to the project :yaml:`name`: + +.. code-block:: yaml + :caption: |bpt.yaml| + + name: acme.widgets + version: 1.2.3 + + # ┌ Implied: ──────────────┐ + │ libraries: │ + │ - name: acme.widgets │ + │ path: . │ + # └────────────────────────┘ + +The above project definition implies a single default library with the same name +as the project itself: "``acme.widgets``". The `library root` of the default +library is always the same as the `project root`, and cannot be changed. + +.. seealso:: + + The :yaml:`libraries` property allows one to specify any number of libraries + within the project. The :yaml:`libraries` property is discussed below: + :ref:`guide.multiple-libs` + +.. note:: + + If your project only defines a single library, you are likely to not need to + use :yaml:`libraries` and can just rely on the implicit default library. + +.. note:: + + If the :yaml:`libraries` property is specified then |bpt| will not generate a + default library. + + +.. _guide.multiple-libs: + +Multiple Libraries in a Project +******************************* + +Multiple libraries can be specified for a single `project` by using the +top-level :yaml:`libraries` property in |bpt.yaml|. :yaml:`libraries` must be an +array, and each element must be a map, and each map element must have both a +:yaml:`name` and a :yaml:`path` property: + +.. code-block:: + :caption: |bpt.yaml| + :emphasize-lines: 4-6 + + name: acme.widgets + version: 1.2.3 + + libraries: + - name: gadgets # Required + path: libs/gadgets # Required + +.. seealso:: + + For more information on using the :yaml:`libraries` array, refer to: + :ref:`proj.lib-properties`. + + .. _libs.library-layout: Library Layout @@ -250,3 +322,115 @@ such files are found. Some source files will be treated differently based on there name. Refer: - :doc:`apps` + + +.. _proj.lib-properties: + +Library Properties in |bpt.yaml| +******************************** + +A |bpt| `project` can declare one or more `libraries ` using the +top-level :ref:`proj.libraries` property in |bpt.yaml|. If the :yaml:`libraries` +property is omitted, |bpt| will instead generate a `default library` for the +project. Most projects will not need to declare explicit :yaml:`libraries` and +can rely on the default library. + +The project's :yaml:`libraries` must be an array, and each element must be a +map, and each map element must at least have both a :yaml:`name` and a +:yaml:`path` property: + +.. code-block:: yaml + :caption: |bpt.yaml| + + name: my-project + version: 1.2.3 + + libraries: + # Declare one library "my-library" + - name: my-library + path: libs/mylib + # Declare a second library + - name: widgets + path: libs/widgets + +Refer to [`YAML`] for a quick-start on the YAML syntax. If nothing else, you can +use YAML's flow-syntax as an "enhanced `JSON`" that supports :yaml:`# comments` +and unquoted identifier keys:: + + { + name: "my-project", + version: "1.2.3", + libraries: [ + {name: "my-library", path: "libs/mylib"}, + {name: "widgets", path: "libs/widgets"}, + ] + } + +The :yaml:`name` property must specify a valid `name` for the library, which +must be unique within the project. + +The :yaml:`path` property specifies the `relative filepath` pointing to the +`library root` for the library. This path must be relative to the `project root` +and may only use forward-slash "``/``" as a `directory +separator`. The :yaml:`path` must not "reach outside" of the project root +directory. A path of a single ASCII dot "``.``" refers to the project root +itself. + +.. note:: + + For the `default library` (if :yaml:`libraries` is omitted), the :yaml:`name` + is the same as the project's name, and the :yaml:`path` is "``.``" (equivalent + to the `project root`). + +.. _lib.properties-dl: + +.. rubric:: Properties + +.. index:: pair: name; library property +.. _lib.name: + +:yaml:`name` : ``string`` + **Required:** The name of the library. Must follow the valid `name` + conventions. This name must be unique within the `project`. + + .. index:: pair: path; library property + .. _lib.path: + +:yaml:`path` : ``string`` + **Required:** The `relative filepath` to the `library root`. + + .. index:: pair: using; library property + .. _lib.using: + +:yaml:`using` : ``string[]`` + *Optional:* The internal `dependencies ` of the library. Must be + the names of other libraries within the same `project`. + + .. index:: pair: test-using; library property + .. _lib.test-using: + +:yaml:`test-using` : ``string[]`` + *Optional:* The internal `test dependencies ` of the + library. Must be the names of other libraries within the same `project`. + + .. index:: pair: dependencies; library property + .. _lib.dependencies: + +:yaml:`dependencies` : (See: :doc:`deps`) + *Optional:* The external `dependencies ` of the library. + + The dependencies here will be merged with the `common dependencies` of the + `project`. + + .. seealso:: :doc:`deps` + + .. index:: pair: test-dependencies; library property + .. _lib.test-dependencies: + +:yaml:`test-dependencies` : (See: :doc:`deps`) + *Optional:* The external `test dependencies ` of the library. + + The dependencies here will be merged with the + `common test-dependencies ` of the `project`. + + .. seealso:: :doc:`deps` diff --git a/docs/guide/packages.rst b/docs/guide/packages.rst deleted file mode 100644 index 47aa0fe2..00000000 --- a/docs/guide/packages.rst +++ /dev/null @@ -1,208 +0,0 @@ -################### -Projects & Packages -################### - -.. default-role:: term -.. highlight:: yaml - -For |bpt| projects and packages, there are a few important terms to understand: - -.. glossary:: - - project - - A |bpt| *project* is a `directory` containing a |bpt.yaml| file and - defines one or more `libraries `. - - Like a `package`, a project has a `name` and a :ref:`version `. For - many purposes, |bpt| will treat a project as a `package` with special - properties. - - |bpt| can capture a project directory as a `package` for distribution and - use in other tools by using the :ref:`cli.pkg-create` subcommand. - - .. seealso:: :ref:`guide.projects` - - package - - A *package* is a `named ` and :ref:`versioned ` collection of - `libraries ` distributed as a unit, available to be "used" to build - additional libraries or `applications `. - - A package contains a |crs.json| file (whereas a `project` would contain a - |bpt.yaml| file). - - When |bpt| is building a dependency solution from some set of dependency - statements, the `name` of the packages are used to create uniqueness: For - every package in a dependency solution, each `name` will only resolve to - only a single version. - - .. seealso:: :term:`CRS package` - - dependency - - A *dependency* specifies a requirement on `libraries ` in an - external `package` in order to build and use the library that has the - dependency. - - A dependency specifies the `name` of an external package, a range of - compatible :ref:`versions `, and a list of one or more libraries - from the depended-on package that are required. - - In |bpt| (and `CRS`), dependencies are attached to individual - `libraries `, and not to the `package` that contains that library. - - .. seealso:: :term:`CRS dependency` - - -.. _guide.projects: - -Understanding Projects -###################### - -When using |bpt|, one is most often working within the scope of a `project`. A -`directory` is a |bpt| *project root* if it contains a ``bpt.yaml``: - -.. glossary:: - - ``bpt.yaml`` - - The ``bpt.yaml`` file is placed in the root `directory` of a `project`. It - defines the `package` attributes of the project, including the `name`, - :ref:`version `, `libraries `, and the - `dependencies ` of those libraries. - - .. rubric:: Example - - .. code-block:: yaml - :linenos: - - # Required: The name of the project - name: my-example-package - # Required: The version of the project - version: 2.5.1-dev - - # Optional: Dependencies - dependencies: - - boost@1.77.0 using asio, filesystem - - project root - - The *project root* of a project is the `directory` that contains the - project's |bpt.yaml| file. - -A |bpt| `project` roughly corresponds to a source control repository and is the -directory that should be opened and modified with an IDE or text editor. - -Within a |bpt.yaml| file, only the :yaml:`name` and :yaml:`version` keys are -required. - - -.. _guide.default-library: - -The Default Library -******************* - -In |bpt|, all code belongs to a `library`. If a |bpt.yaml| file omits the -:yaml:`libs` property, |bpt| will assume that the `project`'s `default library` -lives in the same directory as |bpt.yaml| and has a library :yaml:`name` -equivalent to the project :yaml:`name`: - -.. code-block:: yaml - :caption: |bpt.yaml| - - name: acme.widgets - version: 1.2.3 - - # ┌ Implied: ──────────────┐ - │ libs: │ - │ - name: acme.widgets │ - │ path: . │ - # └────────────────────────┘ - - -The above project definition implies a single default library with the same name -as the project itself: "``acme.widgets``". The `library root` of the default -library is always the same as the `project root`, and cannot be changed. - -.. seealso:: - - The :yaml:`libs` property allows one to specify any number of libraries within - the project. The :yaml:`libs` property is discussed below: - :ref:`guide.multiple-libs` - -.. note:: - - If your project only defines a single library, you are likely to not need to - use :yaml:`libs` and can just rely on the implicit default library. - -.. note:: - - If the :yaml:`libs` property is specified then |bpt| will not generate a - `default library`. - - -.. _guide.multiple-libs: - -Multiple Libraries in a Project -******************************* - -Multiple libraries can be specified for a single `project` by using the -top-level :yaml:`libs` property in |bpt.yaml|. :yaml:`libs` must be an array, -and each element must be a map, and each map element must have both a -:yaml:`name` and a :yaml:`path` property: - -.. code-block:: - :caption: |bpt.yaml| - :emphasize-lines: 4-6 - - name: acme.widgets - version: 1.2.3 - - libs: - - name: gadgets # Required - path: libs/gadgets # Required - -Refer to [`YAML`] for a quick-start on the YAML syntax. If nothing else, you can -use YAML's flow-syntax as an "enhanced `JSON`" that supports :yaml:`# comments` -and unquoted identifier keys:: - - { - name: "acme.widgets", - version: "1.2.3", - libs: [ - {name: "gadgets", path: "libs/gadgets"}, # Both required - ] - } - -The :yaml:`path` property specifies the `relative filepath` pointing to the -`library root` for the library. This path must be relative to the `project -root` and may only use forward-slash "``/``" as a `directory -separator`. The :yaml:`path` must not "reach outside" of the `project root`. A -path of a single ASCII dot "``.``" refers to the project root itself (This is -the path of the `default library` if :yaml:`libs` is omitted). - - -Understanding Packages -###################### - -In |bpt| the term "package" refers to a named+versioned collection of -`libraries `. This can include a `project`, but often refers to some -pre-bundled set of files and directories that contains a |crs.json| file. The -contents of |crs.json| declare all of the properties required to consume a -package and the libraries it contains, but you won't often need to interact with -this file directly. - -Packages are identified by a name/version pair, joined together by an ``@`` -symbol, and with a `package revision number` appended. The version of a package -must be a :ref:`Semantic Version string `. Together, the -``name@version~revision`` string forms the *package ID*, and it must be unique -within a repository. The revision number can often be omitted. - -If you are generating a package from a |bpt| `project` (using the -:ref:`cli.pkg-create` command), the |crs.json| will be synthesized automatically -based on the content of the project's |bpt.yaml| file. - -For this reason a "`project`" can be considered |bpt|'s "high-level" abstraction -of a `package`. A project is intended to be modified directly by an IDE or other -code editor, whereas a package is meant to be consumed by automated tools. diff --git a/docs/guide/projects.rst b/docs/guide/projects.rst new file mode 100644 index 00000000..656f91a8 --- /dev/null +++ b/docs/guide/projects.rst @@ -0,0 +1,232 @@ +################### +Projects & Packages +################### + +.. default-role:: term +.. highlight:: yaml + +For |bpt| projects and packages, there are a few important terms to understand: + +.. glossary:: + + project + + A |bpt| *project* is a `directory` containing a |bpt.yaml| file and + defines one or more `libraries `. + + Like a `package`, a project has a `name` and a :ref:`version `. For + many purposes, |bpt| will treat a project as a package with special + properties. + + |bpt| can capture a project directory as a package for distribution and use + in other tools by using the :ref:`cli.pkg-create` subcommand. + + .. seealso:: :ref:`guide.projects` + + package + + A *package* is a `named ` and :ref:`versioned ` collection of + `libraries ` distributed as a unit, available to be "used" to build + additional libraries or `applications `. + + A package contains a |pkg.json| file (whereas a `project` would contain a + |bpt.yaml| file). + + When |bpt| is building a `dependency` solution from some set of dependency + statements, the `name` of the packages are used to create uniqueness: For + every package in a dependency solution, each `name` may only resolve to only + a single version. + + .. seealso:: :term:`CRS package` + + dependency + + A *dependency* specifies a requirement on `libraries ` in an + external `package` in order to build and use the library that has the + dependency. + + A dependency specifies the `name` of an external package, a range of + compatible :ref:`versions `, and a list of one or more libraries + from the depended-on package that are required. + + In |bpt| (and `CRS`), dependencies are attached to individual libraries, and + not to the package that contains that library. + + .. seealso:: :term:`CRS dependency` + + +.. _guide.projects: + +Understanding Projects +###################### + +When using |bpt|, one is most often working within the scope of a project. A +`directory` is a |bpt| *project root* if it contains a ``bpt.yaml``: + +.. glossary:: + + ``bpt.yaml`` + + The ``bpt.yaml`` file is placed in the root `directory` of a `project`. It + defines the `package` attributes of the project, including the `name`, + :ref:`version `, `libraries `, and the + `dependencies ` of those libraries. + + .. rubric:: Example + + .. code-block:: yaml + :linenos: + + # Required: The name of the project + name: my-example-package + # Required: The version of the project + version: 2.5.1-dev + + Within a |bpt.yaml| file, only the :yaml:`name` and :yaml:`version` keys are + required. + + .. seealso:: :ref:`pkg.bpt.yaml` + + project root + + The *project root* of a `project` is the `directory` that contains the + project's |bpt.yaml| file. + +A |bpt| `project` roughly corresponds to a source control repository and is the +directory that should be opened and modified with an IDE or text editor. + + +Understanding Packages +###################### + +In |bpt| the term "package" refers to a named+versioned collection of +`libraries `. This can include a `project`, but often refers to some +pre-bundled set of files and directories that contains a |pkg.json| file. The +contents of |pkg.json| declare all of the properties required to consume a +package and the libraries it contains, but you won't often need to interact with +this file directly. + +Packages are identified by a name/version pair, joined together by an ``@`` +symbol, and with a `package revision number` appended. The version of a package +must be a :ref:`Semantic Version string `. Together, the +``name@version~revision`` string forms the `package ID`, and it must be unique +within a repository. The revision number can often be omitted. + +If you are generating a package from a |bpt| `project` (using the +:ref:`cli.pkg-create` command), the |pkg.json| will be synthesized automatically +based on the content of the project's |bpt.yaml| file. + +For this reason a "`project`" can be considered |bpt|'s "high-level" abstraction +of a `package`. A project is intended to be modified directly by an IDE or other +code editor, whereas a package is meant to be consumed by automated tools. + + +.. _pkg.bpt.yaml: + +The Project |bpt.yaml| File +########################### + +The |bpt.yaml| file in the root of a `project` is used to set the `package` +attributes of the project, including specifying the `libraries ` of the +project, as well as the `dependencies ` of those libraries. + +In a |bpt.yaml| file, the only two required properties are :yaml:`name` and +:yaml:`version`:: + + # Set the name of the project + name: acme.widgets + # Set the version of the project + version: 4.1.2-dev + +Refer to the `name` and :ref:`versions ` documentation for information +about what makes a valid name and a valid version. + +All other fields are described below. + + +.. index:: + ! pair: name ; project property + +.. _proj.name: + +:yaml:`name` +************ + +**This property is requried** + +Specifies the `package name` of the `project`. Must fit the +:term:`name rules `. + + +.. index:: ! pair: version; project property + +.. _proj.version: + +:yaml:`version` +*************** + +**This property is requried** + +Specifies the `package version` of the `project`. Must be a valid +:ref:`Semantic Version string `. + + +.. index:: ! pair: dependencies; project property + +.. _proj.dependencies: + +:yaml:`dependencies` +******************** + +|prop-optional| + +Specify the `common dependencies` of the `project`. If provided, the value must +be an array of `dependency specifier`\ s. + +.. seealso:: + + - :doc:`deps` + - :ref:`The library dependencies property ` + + +.. index:: ! pair: test-dependencies; project property + +.. _proj.test-dependencies: + +:yaml:`test-dependencies` +************************* + +|prop-optional| + +Specify the `common test-dependencies ` of the `project`. +If provided, the value must be an array of `dependency specifier`\ s. + +.. seealso:: + + - :doc:`deps` + - :ref:`The library test-dependencies property ` + + +.. index:: ! pair: libraries; project property + +.. _proj.libraries: + +:yaml:`libraries` +***************** + +.. |prop-optional| replace:: *This property is optional* + +|prop-optional| + +Specify the `libraries ` of the `project`. If omitted, |bpt| will +generate a `default library` (recommended for most projects). + +.. seealso:: + + - :ref:`proj.lib-properties` + - :doc:`/guide/libraries` + - :ref:`guide.default-library` + - :ref:`guide.multiple-libs` + +If provided, this must be a non-empty array of library maps. + diff --git a/docs/guide/remote-pkgs.rst b/docs/guide/remote-pkgs.rst index 58c6a989..afdf81f3 100644 --- a/docs/guide/remote-pkgs.rst +++ b/docs/guide/remote-pkgs.rst @@ -1,27 +1,54 @@ Remote Packages and Repositories ################################ -.. highlight:: bash +.. |--use-repo| replace:: :option:`--use-repo ` +.. |--no-default-repo| replace:: :option:`--no-default-repo` -|bpt| stores a local database of available packages, along with their -dependency statements and information about how a source distribution thereof -may be obtained. +Unlike most package management systems, |bpt| does not have a separate "install" +step for downloading and using dependencies. Instead each |bpt| operation "uses" +some set of repositories, and data from these repositories are pulled and cached +on-the-fly as required. -Inside the database are *package repositories*, which are remote servers that -contain their own database of packages, and may also contain the packages -themselves. An arbitrary number of package repositories may be added to the -local database. When |bpt| updates its package information, it will download -the package database from each registered remote and import the listings into -its own local database, making them available for download. +The repositories in use by any operation are specified with the |--use-repo| +option, which is accepted by any subcommand that can use package dependencies. +|--use-repo| can be specified any number of times on the command line, and |bpt| +will treat all of the repositories as a pool of packages available for +dependency resolution. + +.. note:: + + In addition to any repositories enabled with |--use-repo|, |bpt| will *by + default* use a default repository at https://repo-3.bpt.pizza/. This can be + disabled with the |--no-default-repo| option. + +.. important:: + + The local package cache **is not** part of the interface and standard + workflow. |bpt| does not "remember" the given |--use-repo| values provided for + a build. Instead, each invocation of |bpt| is considered independent, and + *only* the packages that are available in the repositories specified with + |--use-repo| will be available for dependency resolution. Locally cached + packages are not relevant for the purposes of dependency resolution. + +.. note:: + + The metadata from package repositories is pulled and updated on-the-fly. |bpt| + uses the HTTP Cache-Control__, ETag__, and Last-Modified__ headers to + determine when its cached copy of repository metadata is out-of-date. + + __ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control + __ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag + __ https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified Viewing Available Packages ************************** -The default catalog database is stored in a user-local location, and the -available packages can be listed with ``bpt pkg search``:: +To discover which packages and which versions are available the listing can be +obtained with the :ref:`cli.pkg-search` subcommand:: $ bpt pkg search + Name: abseil Versions: 2018.6.0, 2019.8.8, 2020.2.25 From: repo-1.dds.pizza @@ -38,9 +65,10 @@ available packages can be listed with ``bpt pkg search``:: Versions: 1.70.0, 1.71.0, 1.72.0, 1.73.0 From: repo-1.dds.pizza -Optionally, one can search with a glob/fnmatch-style pattern:: +Optionally, one can search with a fnmatch-style pattern:: $ bpt pkg search 'neo-*' + Name: neo-buffer Versions: 0.2.1, 0.3.0, 0.4.0, 0.4.1, 0.4.2 From: repo-1.dds.pizza @@ -54,143 +82,27 @@ Optionally, one can search with a glob/fnmatch-style pattern:: From: repo-1.dds.pizza -Remote Repositories -******************* - -A remote package repository consists of an HTTP(S) server serving the following: - -1. An accessible directory containing source distributions of various packages, - and -2. An accessible database file that contains a listing of packages and some - repository metadata. - -The exact details of the directory layout and database are not covered here, and -are not necessary to make use of a repository. - -When |bpt| uses a repository, it pulls down the database file and imports its -contents into its own local database, associating the imported package listings -with the remote repository which provides them. Pulling the entire database at -once allows |bpt| to perform much faster dependency resolution and reduces -the round-trips associated with using a dynamic package repository. - - -Adding a Repository -=================== - -Adding a remote repository to the local database is a simple single command:: - - $ bpt pkg repo add "https://repo-1.dds.pizza" - [info ] Pulling repository contents for repo-1.dds.pizza [https://repo-1.dds.pizza/] - -This will tell |bpt| to add ``https://repo-1.dds.pizza`` as a remote -repository and immediately pull its package listings for later lookup. This -initial update can be suppressed with the ``--no-update`` flag. - .. note:: - After the initial ``pkg repo add``, the repository is *not* identified by its - URL, but by its *name*, which is provided by the repository itself. The name - is printed the first time it is added, and can be seen using ``pkg repo ls``. - - -Listing Repositories -==================== - -A list of package repositories can be seen with the ``pkg repo ls`` subcommand:: - - $ bpt pkg repo ls - - -Removing Repositories -===================== + The search packages will include all repositories enabled for the + ``pkg search`` invocation, including the default repository *unless* + |--no-default-repo| is specified. -A repository can be removed by the ``pkg repo remove`` subcommand:: + To search packages available in a specific repository *without* including + packages from the default repository, pass |--use-repo| along with + |--no-default-repo|:: - $ bpt pkg repo remove - -Where ```` is given as the *name* (not URL!) of the repository. - -**Note** that removing a repository will make all of its corresponding remote -packages unavailable, while packages that have been pulled into the local cache -will remain available even after removing a repository. - - -Updating Repository Data -======================== - -Repository data and package listings can be updated with the ``pkg repo update`` -subcommand:: - - $ bpt pkg repo update - -This will pull down the databases of all registered remote repositories. If -|bpt| can detect that a repository's database is unchanged since a prior -update, that update will be skipped. + $ bpt pkg search --use-repo=my-repo.example.org --no-default-repo The Default Repository ********************** -When |bpt| first initializes its local package database, it will add a single -remote repository: ``https://repo-1.dds.pizza/``, which has the name -``repo-1.dds.pizza``. At the time of writing, this is the only official |bpt| -repository, and is populated sparsely with hand-curated and prepared packages. -In the future, the catalog of packages will grow and be partially automated. +The *default repository* is the repository that is always enabled by |bpt| +*unless* |--no-default-repo| is specified. The default repository (at time of +writing) lives at https://repo-3.bpt.pizza/. There is nothing intrinsically special about this repository other than it being -the default when |bpt| first creates its package database. It can be removed -as any other, should one want tighter control over package availability. - - -Managing a Repository -********************* - -A |bpt| repository is simply a directory of static files, so any HTTP server -that can serve from a filesystem can be used as a repository. |bpt| also -ships with a subcommand, ``repo``, that can be used to manage a repository -directory. - - -Initializing a Repository -========================= - -Before anything can be done, a directory should be converted to a repository by -using ``repo init``:: - - $ bpt repo init ./my-repo-dir --name=my-experimental-repo - -This will add the basic metadata into ``./my-repo-dir`` such that |bpt| will -be able to pull package data from it. - -The ``--name`` argument should be used to give the repository a unique name. The -name should be globally unique to avoid collisions: When |bpt| pulls a -repository that declares a given name, it will *replace* the package listings -associated with any repository of that name. As such, generic names like -``main`` or ``packages`` shouldn't be used in production. - - -Listing Contents -================ - -The packages in a repository can be listed using ``bpt repo ls ``. -This will simply print each package identifier that is present in the -repository. - - -Importing Source Distributions -============================== - -If you have a source distribution archive, it can be imported with the -appropriately named ``bpt repo import`` command:: - - $ bpt repo import ./my-repo some-pkg@1.2.3.tar.gz - -Multiple archive paths may be provided to import them all at once. - - -Removing Packages -================= - -A package can be removed from a repository with -``bpt repo remove ``, where ```` is the -``@`` of the package to remove. +the default for |bpt|. It can be disable with |--no-default-repo| or +:envvar:`BPT_NO_DEFAULT_REPO` should one want tighter control over package +availability. diff --git a/docs/guide/terms.rst b/docs/guide/terms.rst index f5d06243..e74e8a47 100644 --- a/docs/guide/terms.rst +++ b/docs/guide/terms.rst @@ -74,6 +74,13 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. another: {nested-object: []}, # Trailing commas are allowed! } + .. note:: Any `JSON` document is also a valid equivalent YAML document. + + .. note:: + + |bpt| parses according to YAML 1.2, so alternate boolean plain scalars + (e.g. "``no``" and "``yes``") and sexagesimal datetimes are not supported. + tweak-headers Special `header files
` that are used to inject configuration @@ -127,21 +134,35 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. .. seealso:: :doc:`tests` compiler + compile + + *Compiling* is the process of transforming human-readable `source code` and + emits a lower-level code intended to be executed. The *compiler* is a + program that performs the compilation. GCC, Visual C++, and Clang are + examples of *compilers*. + + linker + linking + + *Linking* is the process of combining separate translation units (i.e. + compiled source files code) into a program. A *linker* is a program that + performs linking. - A computer program that accepts human-readable `source code` and emits a - lower-level code intended to be executed by a machine. + During linking, references to names across translation units are resolved. + If a name is referenced but its definition is not found, the linker will + most often fail to perform the linking. default library The *default library* of a `project` is the `library` that |bpt| generates - if the :yaml:`libs` project property is omitted in |bpt.yaml|. It will have - the same :yaml:`name` as the project, and its `library root` will be the - same as the `project root`. + if the :yaml:`libraries` project property is omitted in |bpt.yaml|. It will + have the same :yaml:`name` as the project, and its `library root` will be + the same as the `project root`. .. note:: - If the :yaml:`libs` property is specified then |bpt| will not generate a - default library. + If the :yaml:`libraries` property is specified then |bpt| will not + generate a default library. .. seealso:: @@ -225,6 +246,20 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. Test dependencies are declared using the :yaml:`test-dependencies` property in |bpt.yaml|. + common dependencies + + The *common dependencies* of a `project` are the `dependencies ` + that appear at the top-level of the project's |bpt.yaml| file. (Refer: + :ref:`proj.dependencies`) + + These dependencies are added as direct dependencies of every `library` in + the project, whether that is the `default library` or each library in the + :ref:`proj.libraries` array. + + The *common test-dependencies* are the similar but apply only to the + libraries' `test dependencies `. (Refer: + :ref:`proj.test-dependencies`) + package ID A *package ID* is a string that identifies a package. It is composed of the @@ -243,3 +278,11 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. The package revision number is visible on the `package ID` as the number following the tilde ``~`` suffix. + + dependency specifier + + |bpt| allows a few syntaxes to specify a `dependency`. A specifier provides + a `name`, a :ref:`version range `, and some set of `library` names + to use from the external `package`. + + .. seealso:: :ref:`dep-spec` diff --git a/docs/guide/toolchains.rst b/docs/guide/toolchains.rst index 01a5e5bb..2f2be553 100644 --- a/docs/guide/toolchains.rst +++ b/docs/guide/toolchains.rst @@ -1,17 +1,20 @@ .. highlight:: js +.. default-role:: tc-option + +.. |--toolchain| replace:: :option:`--toolchain ` Toolchains ########## One of the core components of |bpt| is that of the *toolchain*. A toolchain -encompasses the environment used to build and link source code, including, but -not limited to: - -#. The executable binaries that constitute the language implementation: - Compilers, linkers, and archive managers. -#. The configuration of those tools, including most options given to those - tools when they are invoked. -#. The set of preprocessor macros and language features that are active during +encompasses the environment used to :term:`compile` and :term:`link ` +source code, including, but not limited to: + +1. The executable binaries that constitute the language implementation: + :term:`Compilers `, :term:`linkers `, and archive managers. +2. The configuration of those tools, including most + :term:`command-line arguments` given to those tools when they are invoked. +3. The set of preprocessor macros and language features that are active during compilation. When a build is run, every file in the entire tree (including dependencies) @@ -21,10 +24,12 @@ This page provides an introduction on how one can make use of toolchains most effectively in your project. .. note:: + **IMPORTANT**: |bpt| will *not* automatically load the Visual C++ - environment. To use Visual C++, |bpt| must be executed from the - appropriate environment in order for the Visual C++ toolchain executables - and files to be available. + environment. To use Visual C++, |bpt| must be executed from the appropriate + environment in order for the Visual C++ toolchain executables and files to + be available. + .. _toolchains.file: @@ -36,7 +41,7 @@ that describes the entire toolchain. When running a build for a project, the |bpt| executable will look in a few locations for a default toolchain, and generate an error if no default toolchain file is found (Refer to :ref:`toolchains.default`). A different toolchain can be provided by passing -the toolchain file for the ``--toolchain`` (or ``-t``) option on the command +the toolchain file for the |--toolchain| (or ``-t``) option on the command line:: $ bpt build -t my-toolchain.json5 @@ -50,14 +55,12 @@ Built-in Toolchains ******************* For convenience, |bpt| includes several built-in toolchains that can be -accessed in the ``--toolchain`` command-line option using a colon ``:`` +accessed in the |--toolchain| command-line option using a colon ``:`` prefix:: $ bpt build -t :gcc -|bpt| will treat the leading colon (``:``) as a name for a built-in -toolchain (this means that a toolchain's filepath may not begin with a colon). - +|bpt| will treat the leading colon (``:``) as a name for a built-in toolchain. There are several built-in toolchains that may be specified: ``:gcc`` @@ -95,10 +98,10 @@ The following pseudo-toolchains are also available: Providing a Default Toolchain File ********************************** -If you do not wish to provide a new toolchain for every individual project, -and the built-in toolchains do not suit your needs, you can write a toolchain -file to one of a few predefined paths, and |bpt| will find and use it for the -build. The following directories are searched, in order: +If you do not wish to provide a new toolchain for every individual project, and +the built-in toolchains do not suit your needs, you can write a toolchain file +to one of a few predefined paths, and |bpt| will find and use it for the build. +The following directories are searched, in order: #. ``$pwd/`` - If the working directory contains a toolchain file, it will be used as the default. @@ -111,12 +114,11 @@ build. The following directories are searched, in order: In each directory, it will search for ``toolchain.json5``, ``toolchain.jsonc``, or ``toolchain.json``. -The ``$bpt_config_dir`` directory is the |bpt| subdirectory of the -user-local configuration directory. +The ``$bpt_config_dir`` directory is the |bpt| subdirectory of the user-local +configuration directory. The user-local config directory is ``$XDG_CONFIG_DIR`` or ``~/.config`` on -Linux, ``~/Library/Preferences`` on macOS, and ``~/AppData/Roaming`` on -Windows. +Linux, ``~/Library/Preferences`` on macOS, and ``~/AppData/Roaming`` on Windows. Toolchain Definitions @@ -133,16 +135,16 @@ simply one line: compiler_id: "" } -where ```` is one of the known ``compiler_id`` options (See the -toolchain option reference). |bpt| will infer common suitable defaults for -the remaining options based on the value of ``compiler_id``. +where ```` is one of the known `compiler_id` options. |bpt| will +infer common suitable defaults for the remaining options based on the value of +`compiler_id`. -For example, if you specify ``gnu``, then |bpt| will assume ``gcc`` to be the -C compiler, ``g++`` to be the C++ compiler, and ``ar`` to be the library -archiving tool. +For example, if you specify ``gnu``, then |bpt| will assume ``gcc`` to be the C +compiler, ``g++`` to be the C++ compiler, and ``ar`` to be the library archiving +tool. -If you know that your compiler executable has a different name, you can -specify them with additional options: +If you know that your compiler executable has a different name, you can specify +them with additional options: .. code-block:: @@ -152,11 +154,11 @@ specify them with additional options: cxx_compiler: 'g++-9', } -|bpt| will continue to infer other options based on the ``compiler_id``, but -will use the provided executable names when compiling files for the respective +|bpt| will continue to infer other options based on the `compiler_id`, but will +use the provided executable names when compiling files for the respective languages. -To specify compilation flags, the ``flags`` option can be used: +To specify compilation flags, the `flags ` option can be used: .. code-block:: @@ -166,9 +168,10 @@ To specify compilation flags, the ``flags`` option can be used: } .. note:: - Use ``warning_flags`` to specify options regarding compiler warnings. -Flags for linking executables can be specified with ``link_flags``: + Use `warning_flags` to specify options regarding compiler warnings. + +Flags for linking executables can be specified with `link_flags`: .. code-block:: @@ -195,7 +198,7 @@ and double ``"`` quote characters as argument delimiters. If an option is given a list of strings instead, then each string in that array is treated as a full command line argument and is passed as such. -For example, this sample with ``flags``:: +For example, this sample with `flags `:: { flags: "-fsanitize=address -fPIC" @@ -212,6 +215,8 @@ else shell-like. It does not expand environment variables, nor does it expand globs and wildcards. +.. _compiler_id: + ``compiler_id`` --------------- @@ -235,25 +240,28 @@ Valid values are: ----------------------------------- Names/paths of the C and C++ compilers, respectively. Defaults will be inferred -from ``compiler_id``. +from `compiler_id`. +.. _c_version: +.. _cxx_version: + ``c_version`` and ``cxx_version`` --------------------------------- Specify the language versions for C and C++, respectively. By default, |bpt| will not set any language version. Using this option requires that the -``compiler_id`` be specified (Or the ``lang_version_flag_template`` advanced +`compiler_id` be specified (Or the `lang_version_flag_template` advanced setting). -Examples of ``c_version`` values are: +Examples of `c_version ` values are: - ``c89`` - ``c99`` - ``c11`` - ``c18`` -Examples of ``cxx_version`` values are: +Examples of `cxx_version ` values are: - ``c++14`` - ``c++17`` @@ -265,24 +273,26 @@ the language version being passed. To enable GNU language extensions on GNU compilers, one can values like ``gnu++20``, which will result in ``-std=gnu++20`` being passed. Likewise, if the language version is "experimental" in your GCC release, you may set -``cxx_version`` to the appropriate experimental version name, e.g. ``"c++2a"`` -for ``-std=c++2a``. +`cxx_version ` to the appropriate experimental version name, e.g. +``"c++2a"`` for ``-std=c++2a``. -For MSVC, setting ``cxx_version`` to ``c++latest`` will result in +For MSVC, setting `cxx_version ` to ``c++latest`` will result in ``/std:c++latest``. **Beware** that this is an unstable setting value that could change the major language version in a future MSVC update. +.. _warning_flags: + ``warning_flags`` ----------------- Provide *additional* compiler flags that should be used to enable warnings. This -option is stored separately from ``flags``, as these options may be +option is stored separately from `flags `, as these options may be enabled/disabled separately depending on how |bpt| is invoked. .. note:: - If ``compiler_id`` is provided, a default set of warning flags will be + If `compiler_id` is provided, a default set of warning flags will be provided when warnings are enabled. Adding flags to this toolchain option will *append* flags to the basis @@ -293,12 +303,16 @@ enabled/disabled separately depending on how |bpt| is invoked. Refer to :ref:`toolchains.opts.base_warning_flags` for more information. +.. _flags: + ``flags``, ``c_flags``, and ``cxx_flags`` ----------------------------------------- Specify *additional* compiler options, possibly per-language. +.. _link_flags: + ``link_flags`` -------------- @@ -318,14 +332,14 @@ Specify *additional* link options to use when linking executables. ``optimize`` ------------ -Boolean option (``true`` or ``false``) to enable/disable optimizations. Default -is ``false``. +Boolean option (|true| or |false|) to enable/disable optimizations. Default +is |false|. ``debug`` --------- -Bool or string. Default is ``false``. If ``true`` or ``"embedded"``, generates +Bool or string. Default is |false|. If |true| or ``"embedded"``, generates debug information embedded in the compiled binaries. If ``"split"``, generates debug information in a separate file from the binaries. @@ -340,20 +354,20 @@ debug information in a separate file from the binaries. Select the language runtime/standard library options. Must be an object, and supports two keys: ``static`` - A boolean. If ``true``, the runtime and standard libraries will be - static-linked into the generated binaries. If ``false``, they will be - dynamically linked. Default is ``true`` with MSVC, and ``false`` with GCC + A boolean. If |true|, the runtime and standard libraries will be + static-linked into the generated binaries. If |false|, they will be + dynamically linked. Default is |true| with MSVC, and |false| with GCC and Clang. ``debug`` - A boolean. If ``true``, the debug versions of the runtime and standard + A boolean. If |true|, the debug versions of the runtime and standard library will be compiled and linked into the generated binaries. If - ``false``, the default libraries will be used. + |false|, the default libraries will be used. **On MSVC** the default value depends on the top-level ``/debug`` option: If - ``/debug`` is not ``false``, then ``/runtime/debug`` defaults to ``true``. + ``/debug`` is not |false|, then ``/runtime/debug`` defaults to |true|. - **On GCC and Clang** the default value is ``false``. + **On GCC and Clang** the default value is |false|. .. note:: @@ -363,7 +377,7 @@ Select the language runtime/standard library options. Must be an object, and sup .. note:: - On GNU and Clang, setting ``/runtime/debug`` to ``true`` will compile all + On GNU and Clang, setting ``/runtime/debug`` to |true| will compile all files with the ``_GLIBCXX_DEBUG`` and ``_LIBCPP_DEBUG=1`` preprocessor definitions set. **Translation units compiled with these macros are definitively ABI-incompatible with TUs that have been compiled without these @@ -391,7 +405,7 @@ Advanced Options Reference ************************** The options below are probably not good to tweak unless you *really* know what -you are doing. Their values will be inferred from ``compiler_id``. +you are doing. Their values will be inferred from `compiler_id`. Command Templates @@ -517,6 +531,8 @@ On MSVC, this defaults to ``/D [def]``. On GNU-like compilers, this is ``-D [def]``. +.. _lang_version_flag_template: + ``lang_version_flag_template`` ------------------------------ @@ -524,7 +540,7 @@ Set the flag template string for the language-version specifier for the compiler command line. This template expects a single placeholder: ``[version]``, which is the version -string passed for ``c_version`` or ``cxx_version``. +string passed for `c_version` or `cxx_version`. On MSVC, this defaults to ``/std:[version]``. On GNU-like compilers, it defaults to ``-std=[version]``. @@ -553,13 +569,13 @@ and executable files, respectively. When you compile your project and request warning flags, |bpt| will concatenate the warning flags from this option with the flags provided by -``warning_flags``. This option is "advanced," because it provides a set of -defaults based on the ``compiler_id``. +`warning_flags`. This option is "advanced," because it provides a set of +defaults based on the `compiler_id`. On GNU-like compilers, the base warning flags are ``-Wall -Wextra -Wpedantic -Wconversion``. On MSVC the default flag is ``/W4``. -For example, if you set ``warning_flags`` to ``"-Werror"`` on a GNU-like +For example, if you set `warning_flags` to ``"-Werror"`` on a GNU-like compiler, the resulting command line will contain ``-Wall -Wextra -Wpedantic -Wconversion -Werror``. @@ -569,10 +585,9 @@ compiler, the resulting command line will contain ``-Wall -Wextra -Wpedantic ``base_flags``, ``base_c_flags``, and ``base_cxx_flags`` -------------------------------------------------------- -When you compile your project, |bpt| uses a set of default flags appropriate -to the target language and compiler. These flags are always included in the -compile command and are inserted in addition to those flags provided by -``flags``, ``c_flags``, and ``cxx_flags``. +When you compile your project, |bpt| uses a set of default flags appropriate to +the target language and compiler. These flags are always included in the compile +command and are inserted in addition to those flags provided by `flags`. On GNU-like compilers, the base flags are ``-fPIC -pthread``. On MSVC the default flags are ``/EHsc /nologo /permissive-`` for C++ and ``/nologo @@ -587,8 +602,8 @@ independent from ``base_flags``; that is, providing ``base_c_flags`` or ``base_flags`` value, and vice-versa. Empty values are acceptable, should you need to simply prohibit one or more of the defaults from being used. -For example, if you set ``flags`` to ``-ansi`` on a GNU-like compiler, the +For example, if you set `flags ` to ``-ansi`` on a GNU-like compiler, the resulting command line will contain ``-fPIC -pthread -ansi``. If, additionally, you set ``base_flags`` to ``-fno-builtin`` and ``base_cxx_flags`` to -``-fno-exceptions``, the generated command will include ``-fno-builtin --fno-exceptions -ansi`` for C++ and ``-fno-builtin -ansi`` for C. +``-fno-exceptions``, the generated command will include +``-fno-builtin -fno-exceptions -ansi`` for C++ and ``-fno-builtin -ansi`` for C. diff --git a/docs/howto/deps.rst b/docs/howto/deps.rst index 3dbfca10..28d2ca5e 100644 --- a/docs/howto/deps.rst +++ b/docs/howto/deps.rst @@ -30,7 +30,7 @@ The *Novel*: compilation to your own project will be used to perform incremental compilation of your dependencies as well. -.. seealso:: :doc:`/guide/interdeps` +.. seealso:: :doc:`/guide/deps` Listing Package Dependencies @@ -44,7 +44,7 @@ to find a ``spdlog`` package. We can search via :ref:`cli.pkg-search`:: Name: spdlog Versions: 1.4.0, 1.4.1, 1.4.2, 1.5.0, 1.6.0, 1.6.1, 1.7.0, 1.8.0, 1.8.1, 1.8.2, 1.8.3, 1.8.4, 1.8.5, 1.9.0, 1.9.1, 1.9.2 - From: https://repo-2.dds.pizza/ + From: https://repo-3.bpt.pizza/ In the output above, we can see one ``spdlog`` group with several available versions. Let's pick the newest available, ``1.9.2``. diff --git a/docs/prolog.rst b/docs/prolog.rst new file mode 100644 index 00000000..0225541d --- /dev/null +++ b/docs/prolog.rst @@ -0,0 +1,33 @@ + +.. role:: bpt-name(literal) + :class: bpt-name + +.. |bpt| replace:: :bpt-name:`bpt` + +.. |code-open| raw:: html + + + +.. |code-close| raw:: html + + + +.. |bpt.yaml| replace:: |code-open|\ :term:`bpt.yaml`\ |code-close| + +.. |pkg.json| replace:: |code-open|\ :ref:`pkg.json`\ |code-close| + +.. role:: yaml(code) + :language: yaml + :class: highlight + +.. role:: cpp(code) + :language: cpp + :class: highlight + +.. |#include| replace:: :cpp:`#include` + + +.. |true| replace:: :cpp:`true` +.. |false| replace:: :cpp:`false` + +.. role:: tc-option(ref) From 84f4dde6255d75a17981b608f6f7f1da347032d8 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 11 May 2022 21:39:08 -0600 Subject: [PATCH 27/62] Fix default repo name in cli help --- src/bpt/cli/options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 2f70fa98..1843d5b0 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -116,7 +116,7 @@ struct setup { argument no_default_repo_arg{ .long_spellings = {"no-default-repo"}, .short_spellings = {"NDR"}, - .help = "Do not consult the default package repository [repo-2.dds.pizza]", + .help = "Do not consult the default package repository [repo-3.bpt.pizza]", .nargs = 0, .action = store_false(opts.use_default_repo), }; From ab548c4bb36236319e4bc99aa08a2d9c0fe960ee Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 11 May 2022 21:39:59 -0600 Subject: [PATCH 28/62] Unused script --- tools/docs-watch.sh | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 tools/docs-watch.sh diff --git a/tools/docs-watch.sh b/tools/docs-watch.sh deleted file mode 100644 index 3370cf1d..00000000 --- a/tools/docs-watch.sh +++ /dev/null @@ -1,16 +0,0 @@ -set -eu - -THIS_SCRIPT=$(readlink -m $0) -HERE=$(dirname ${THIS_SCRIPT}) -ROOT=$(dirname ${HERE}) - -while true; do - echo "Watching for changes..." - inotifywait -r ${ROOT}/docs/ -q \ - -e modify \ - -e close_write \ - -e move \ - -e delete \ - -e create - make docs || : -done From 0f611298259ade74eb7344c86994711c3bcb23ef Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 11 May 2022 23:34:34 -0600 Subject: [PATCH 29/62] Return packages for version in desc order by revision --- src/bpt/crs/cache_db.cpp | 1 + src/bpt/crs/cache_db.hpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/bpt/crs/cache_db.cpp b/src/bpt/crs/cache_db.cpp index 23817300..ab8b7090 100644 --- a/src/bpt/crs/cache_db.cpp +++ b/src/bpt/crs/cache_db.cpp @@ -145,6 +145,7 @@ cache_db::for_package(bpt::name const& name, semver::version const& version) con SELECT pkg_id, remote_id, json FROM enabled_packages WHERE name = ? AND version = ? + ORDER BY pkg_version DESC )"); st.bindings() = std::forward_as_tuple(name.str, version.to_string()); return cache_entries_for_query(std::move(st)); diff --git a/src/bpt/crs/cache_db.hpp b/src/bpt/crs/cache_db.hpp index ba8c18a1..953cb2a0 100644 --- a/src/bpt/crs/cache_db.hpp +++ b/src/bpt/crs/cache_db.hpp @@ -85,6 +85,8 @@ class cache_db { * * @param name The name of a package * @param version The version of the package + * + * @note The package range returned is ordered in descending order by the pkg-version */ [[nodiscard]] neo::any_input_range for_package(bpt::name const& name, semver::version const& version) const; From a8f9fe3a7a5b86f4efe2d472ea6d516bf54a29dc Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 11 May 2022 23:35:40 -0600 Subject: [PATCH 30/62] Ensure the 'pkg create' temporary tgz is deleted --- src/bpt/crs/repo.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bpt/crs/repo.cpp b/src/bpt/crs/repo.cpp index 8f20d66c..4657118c 100644 --- a/src/bpt/crs/repo.cpp +++ b/src/bpt/crs/repo.cpp @@ -147,6 +147,7 @@ void repository::import_dir(path_ref dirpath) { auto tmp_tgz = pkg_dir() / (prep_dir.path().filename().string() + ".tgz"); neo::compress_directory_targz(prep_dir.path(), tmp_tgz); + neo_defer { std::ignore = ensure_absent(tmp_tgz); }; if (pkg.id.revision < 1) { BOOST_LEAF_THROW_EXCEPTION(e_repo_import_invalid_pkg_version{ From 8231c23d7dab717f623ccdbef9bb79837613ffef Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 11 May 2022 23:36:09 -0600 Subject: [PATCH 31/62] Allow specifying the pkg-version in 'pkg create' --- src/bpt/cli/cmd/pkg_create.cpp | 9 +++++++++ src/bpt/cli/options.cpp | 5 +++++ src/bpt/cli/options.hpp | 4 ++++ src/bpt/sdist/dist.cpp | 1 + src/bpt/sdist/dist.hpp | 3 ++- 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/bpt/cli/cmd/pkg_create.cpp b/src/bpt/cli/cmd/pkg_create.cpp index 99a00e8e..a5be19b9 100644 --- a/src/bpt/cli/cmd/pkg_create.cpp +++ b/src/bpt/cli/cmd/pkg_create.cpp @@ -21,9 +21,18 @@ int pkg_create(const options& opts) { .project_dir = opts.absolute_project_dir_path(), .dest_path = {}, .force = opts.if_exists == if_exists::replace, + .revision = opts.pkg.create.revision, }; + if (params.revision < 1) { + bpt_log( + error, + ".bold.cyan[--revision] must be greater than or equal to one '1' (Got .bold.red[{}])"_styled, + params.revision); + return 1; + } return bpt_leaf_try { auto sd = sdist::from_directory(params.project_dir); + sd.pkg.id.revision = params.revision; auto default_filename = fmt::format("{}.tar.gz", sd.pkg.id.to_string()); auto filepath = opts.out_path.value_or(fs::current_path() / default_filename); create_sdist_targz(filepath, params); diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 1843d5b0..28c084db 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -301,6 +301,11 @@ struct setup { = "Destination path for the source distribution archive"; pkg_create_cmd.add_argument(if_exists_arg.dup()).help = "What to do if the destination names an existing file"; + pkg_create_cmd.add_argument({ + .long_spellings = {"revision"}, + .help = "The revision number of the generated package (The CRS \"pkg-version\")", + .action = put_into(opts.pkg.create.revision), + }); } void setup_pkg_search_cmd(argument_parser& pkg_search_cmd) noexcept { diff --git a/src/bpt/cli/options.hpp b/src/bpt/cli/options.hpp index 462162f9..41fbe726 100644 --- a/src/bpt/cli/options.hpp +++ b/src/bpt/cli/options.hpp @@ -175,6 +175,10 @@ struct options { /// The 'bpt pkg' subcommand pkg_subcommand subcommand; + struct { + int revision = 1; + } create; + /** * @brief Paramters for 'bpt pkg prefetch' */ diff --git a/src/bpt/sdist/dist.cpp b/src/bpt/sdist/dist.cpp index 39a33f1d..c0ba7c42 100644 --- a/src/bpt/sdist/dist.cpp +++ b/src/bpt/sdist/dist.cpp @@ -104,6 +104,7 @@ sdist bpt::create_sdist_in_dir(path_ref out, const sdist_params& params) { for (const crs::library_info& lib : in_sd.pkg.libraries) { sdist_copy_library(out, in_sd, lib, params); } + in_sd.pkg.id.revision = params.revision; fs::create_directories(out); bpt::write_file(out / "pkg.json", in_sd.pkg.to_json(2)); diff --git a/src/bpt/sdist/dist.hpp b/src/bpt/sdist/dist.hpp index 48f73d3c..6fd0c9db 100644 --- a/src/bpt/sdist/dist.hpp +++ b/src/bpt/sdist/dist.hpp @@ -8,7 +8,8 @@ namespace bpt { struct sdist_params { fs::path project_dir; fs::path dest_path; - bool force = false; + bool force = false; + int revision = 1; }; struct sdist { From 64ab1f48881c6a95104ba034cf80dbaa3072e8f0 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 14 May 2022 20:03:31 -0600 Subject: [PATCH 32/62] Support trace logging of SQLite operations --- conf/bpt.tweaks.hpp | 21 +++++++++++++++++++++ src/bpt.main.cpp | 22 +++++++++++++++++++++- src/bpt/cli/cmd/repo_validate.cpp | 27 +++++---------------------- src/bpt/config.cpp | 5 +++++ src/bpt/config.hpp | 20 ++++++++++++++++++++ 5 files changed, 72 insertions(+), 23 deletions(-) create mode 100644 conf/bpt.tweaks.hpp create mode 100644 src/bpt/config.cpp create mode 100644 src/bpt/config.hpp diff --git a/conf/bpt.tweaks.hpp b/conf/bpt.tweaks.hpp new file mode 100644 index 00000000..72f38dbc --- /dev/null +++ b/conf/bpt.tweaks.hpp @@ -0,0 +1,21 @@ +#pragma once + +// See bpt/config.hpp for information about this file. + +/* +## ## ####### ######## ######## ## +### ## ## ## ## ## #### +#### ## ## ## ## ## ## +## ## ## ## ## ## ###### +## #### ## ## ## ## ## +## ### ## ## ## ## #### +## ## ####### ## ######## ## +*/ + +/** + * DO NOT COMMIT CHANGES TO THIS FILE. + * + * This file is for local development tweaking only. + */ + +namespace bpt::config {} // namespace bpt::config diff --git a/src/bpt.main.cpp b/src/bpt.main.cpp index 4329fe5c..68b2f33a 100644 --- a/src/bpt.main.cpp +++ b/src/bpt.main.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -12,6 +13,9 @@ #include #include #include +#include +#include +#include #include #include @@ -141,7 +145,23 @@ int main_fn(std::string_view program_name, const std::vector& argv) // We want ^C to behave as-normal for 'new' bpt::install_signal_handlers(); } - bpt::log::current_log_level = opts.log_level; + bpt::log::current_log_level = opts.log_level; + neo::opt_listener log_sqlite3 = [&](neo::sqlite3::event::step ev) { + auto msg = neo::sqlite3::error_category().message(static_cast(ev.ec)); + bpt_log(trace, "SQLite step: .bold.white[{}]"_styled, ev.st.expanded_sql_string()); + if (neo::sqlite3::is_error_rc(ev.ec)) { + bpt_log(trace, + " Error: .bold.red[{}]: .bold.yellow[{}]"_styled, + msg, + ev.st.connection().error_message()); + } else { + bpt_log(trace, " Okay: .bold.green[{}]"_styled, msg); + } + }; + + if (opts.log_level >= bpt::log::level::trace and bpt::config::enable_sqlite3_trace()) { + log_sqlite3.start_listening(); + } return bpt::cli::dispatch_main(opts); } diff --git a/src/bpt/cli/cmd/repo_validate.cpp b/src/bpt/cli/cmd/repo_validate.cpp index dbbc9094..491ecc03 100644 --- a/src/bpt/cli/cmd/repo_validate.cpp +++ b/src/bpt/cli/cmd/repo_validate.cpp @@ -86,29 +86,12 @@ int repo_validate(const options& opts) { cache.enable_remote(url); } - neo::sqlite3::transaction_guard tr{db.sqlite3_db()}; - neo_defer { tr.rollback(); }; + auto fs_url = neo::url::for_file_path(repo.root()); + cache.sync_remote(fs_url); + cache.enable_remote(fs_url); - auto tmp_remote_id = *neo::sqlite3::one_cell(db.prepare(R"( - INSERT INTO bpt_crs_remotes (url, unique_name, revno) - VALUES ('tmp-validate', '--- tmp-validation-repo ---', 1) - RETURNING remote_id - )"_sql)); - neo::sqlite3::exec(db.prepare("INSERT INTO bpt_crs_enabled_remotes (remote_id) VALUES(?)"_sql), - tmp_remote_id) - .throw_if_error(); - - neo::sqlite3::exec_each( // - db.prepare(R"( - INSERT INTO bpt_crs_packages(json, remote_id, remote_revno) - VALUES (?, ?, 1) - )"_sql), - repo.all_packages() | neo::lref | std::views::transform([&](const auto& pkg) { - return std::make_tuple(pkg.to_json(), tmp_remote_id); - })) - .throw_if_error(); - - for (auto&& pkg : repo.all_packages()) { + // We only want to validate packages that are the max revision: + for (auto&& pkg : repo.all_latest_rev_packages()) { bpt::cancellation_point(); const bool okay = try_it(pkg, cache); if (!okay) { diff --git a/src/bpt/config.cpp b/src/bpt/config.cpp new file mode 100644 index 00000000..e36dcb12 --- /dev/null +++ b/src/bpt/config.cpp @@ -0,0 +1,5 @@ +#include "./config.hpp" + +#include + +bool bpt::config::defaults::enable_sqlite3_trace() { return bpt::getenv_bool("BPT_SQLITE3_TRACE"); } diff --git a/src/bpt/config.hpp b/src/bpt/config.hpp new file mode 100644 index 00000000..5dee52f5 --- /dev/null +++ b/src/bpt/config.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace bpt::config { + +namespace defaults { + +/** + * @brief Control whether --log-level=trace writes log events for SQLite statement step() + * invocations. This default returns true if the BPT_SQLITE3_TRACE environment variable is + * set to a truthy value. + */ +bool enable_sqlite3_trace(); + +} // namespace defaults + +using namespace defaults; + +} // namespace bpt::config From 394a8d62fa01a6a7b418dc72c24a2e4a3f04ba77 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 14 May 2022 20:04:23 -0600 Subject: [PATCH 33/62] Only store the latest pkg-version of a package in the local cache --- src/bpt/crs/cache_db.cpp | 8 ++++---- src/bpt/crs/repo.cpp | 26 +++++++++++++++++++++++++- src/bpt/crs/repo.hpp | 1 + 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/bpt/crs/cache_db.cpp b/src/bpt/crs/cache_db.cpp index ab8b7090..7f049069 100644 --- a/src/bpt/crs/cache_db.cpp +++ b/src/bpt/crs/cache_db.cpp @@ -85,7 +85,7 @@ cache_db cache_db::open(unique_database& db) { GENERATED ALWAYS AS (json_extract(json, '$.pkg-version')) STORED, - UNIQUE (name, version, pkg_version, remote_id) + UNIQUE (name, version, remote_id) ); )"_sql); }).value(); @@ -486,9 +486,9 @@ void cache_db::sync_remote(const neo::url_view& url_) const { auto& update_pkg_st = db.prepare(R"( INSERT INTO bpt_crs_packages (json, remote_id, remote_revno) VALUES (?1, ?2, ?3) - ON CONFLICT(name, version, pkg_version, remote_id) DO UPDATE - SET json=excluded.json, - remote_revno=?3 + ON CONFLICT(name, version, remote_id) DO UPDATE + SET json=excluded.json, remote_revno=?3 + WHERE json_extract(excluded.json, '$.pkg-version') >= pkg_version )"_sql); for (auto meta : remote_packages) { if (!meta.has_value()) { diff --git a/src/bpt/crs/repo.cpp b/src/bpt/crs/repo.cpp index 4657118c..bfa312fe 100644 --- a/src/bpt/crs/repo.cpp +++ b/src/bpt/crs/repo.cpp @@ -178,7 +178,31 @@ void repository::import_dir(path_ref dirpath) { } neo::any_input_range repository::all_packages() const { - auto& q = _prepare("SELECT meta_json FROM crs_repo_packages ORDER BY package_id"_sql); + auto& q = _prepare(R"( + SELECT meta_json + FROM crs_repo_packages AS this + ORDER BY package_id + )"_sql); + auto rst = neo::copy_shared(q.auto_reset()); + return db_query(q) + | std::views::transform([pin = rst](auto tup) -> package_info { + auto [json_str] = tup; + return package_info::from_json_str(json_str); + }); +} + +neo::any_input_range repository::all_latest_rev_packages() const { + auto& q = _prepare(R"( + SELECT meta_json + FROM crs_repo_packages AS this + WHERE NOT EXISTS( + SELECT 1 FROM crs_repo_packages AS other + WHERE other.pkg_version > this.pkg_version + AND other.version = this.version + AND other.name = this.name + ) + ORDER BY package_id + )"_sql); auto rst = neo::copy_shared(q.auto_reset()); return db_query(q) | std::views::transform([pin = rst](auto tup) -> package_info { diff --git a/src/bpt/crs/repo.hpp b/src/bpt/crs/repo.hpp index f026aee3..a9ed3a4b 100644 --- a/src/bpt/crs/repo.hpp +++ b/src/bpt/crs/repo.hpp @@ -40,6 +40,7 @@ class repository { void remove_pkg(const package_info&); neo::any_input_range all_packages() const; + neo::any_input_range all_latest_rev_packages() const; }; struct ev_repo_imported_package { From 9dc659ebc22c10b41e878d5bfd0bd2ae96ac49e8 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 14 May 2022 20:06:07 -0600 Subject: [PATCH 34/62] Friendship ended with libman, now JSON is my best friend --- src/bpt/build/builder.cpp | 71 +++++++++++++++++--------------- src/bpt/build/params.hpp | 3 +- src/bpt/cli/cmd/build.cpp | 11 +++-- src/bpt/cli/cmd/build_common.cpp | 2 +- src/bpt/cli/cmd/build_deps.cpp | 13 +++--- src/bpt/cli/cmd/compile_file.cpp | 9 ++-- src/bpt/cli/error_handler.cpp | 12 ++++-- src/bpt/cli/options.cpp | 18 +++----- src/bpt/cli/options.hpp | 2 +- src/bpt/deps.cpp | 5 ++- src/bpt/deps.hpp | 9 ++++ 11 files changed, 83 insertions(+), 72 deletions(-) diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index 6c96c976..4f1b2058 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,8 @@ using namespace bpt; using namespace fansi::literals; +using json = nlohmann::ordered_json; + namespace { void log_failure(const test_failure& fail) { @@ -174,47 +177,49 @@ prepare_ureqs(const build_plan& plan, const toolchain& toolchain, path_ref out_r return usage_requirements(std::move(ureqs)); } -void write_lml(build_env_ref env, const library_plan& lib, path_ref lml_path) { - fs::create_directories(lml_path.parent_path()); - auto out = bpt::open_file(lml_path, std::ios::binary | std::ios::out); - //! out << "Type: Library\n" - //! << "Name: " << lib.name().str << '\n' - //! << "Include-Path: " << lib.library_().public_include_dir().generic_string() << '\n'; - for (auto&& use : lib.lib_uses()) { - out << "Uses: " << use.namespace_ << "/" << use.name << '\n'; +json get_built_lib(build_env_ref env, const library_plan& lib) { + auto ret = json::object(); + ret.emplace("name", std::string(lib.name())); + if (auto const& ar = lib.archive_plan(); ar.has_value()) { + ret.emplace("path", + normalize_path(env.output_root / ar->calc_archive_file_path(env.toolchain)) + .generic_string()); } - //! for (auto&& link : lib.links()) { - //! out << "Links: " << link.namespace_ << "/" << link.name << '\n'; - //! } - if (auto&& arc = lib.archive_plan()) { - out << "Path: " - << (env.output_root / arc->calc_archive_file_path(env.toolchain)).generic_string() - << '\n'; + ret.emplace("include-path", normalize_path(lib.public_include_dir()).generic_string()); + auto uses = json::array(); + for (auto&& use : lib.lib_uses()) { + uses.push_back(json::object({ + {"package", use.namespace_}, + {"library", use.name}, + })); } + ret.emplace("uses", std::move(uses)); + return ret; } -void write_lmp(build_env_ref env, const package_plan& pkg, path_ref lmp_path) { - fs::create_directories(lmp_path.parent_path()); - auto out = bpt::open_file(lmp_path, std::ios::binary | std::ios::out); - out << "Type: Package\n" - << "Name: " << pkg.name() << '\n' - << "Namespace: " << pkg.name() << '\n'; +json get_built_pkg(build_env_ref env, const package_plan& pkg) { + auto ret = json::object(); + auto libs = json::array(); + for (const auto& lib : pkg.libraries()) { - auto lml_path = lmp_path.parent_path() / (lib.qualified_name() + ".lml"); - write_lml(env, lib, lml_path); - out << "Library: " << lml_path.generic_string() << '\n'; + auto l = get_built_lib(env, lib); + libs.push_back(std::move(l)); } + + ret.emplace("libraries", std::move(libs)); + return ret; } -void write_lmi(build_env_ref env, const build_plan& plan, path_ref base_dir, path_ref lmi_path) { - fs::create_directories(fs::absolute(lmi_path).parent_path()); - auto out = bpt::open_file(lmi_path, std::ios::binary | std::ios::out); - out << "Type: Index\n"; +void write_built_json(build_env_ref env, const build_plan& plan, path_ref json_path) { + auto root = json::object({{"version", 1}}); + auto pkgs = json::object(); + fs::create_directories(fs::absolute(json_path).parent_path()); for (const auto& pkg : plan.packages()) { - auto lmp_path = base_dir / "_libman" / (pkg.name() + ".lmp"); - write_lmp(env, pkg, lmp_path); - out << "Package: " << pkg.name() << "; " << lmp_path.generic_string() << '\n'; + auto p = get_built_pkg(env, pkg); + pkgs.emplace(pkg.name(), std::move(p)); } + root.emplace("packages", std::move(pkgs)); + bpt::write_file(json_path, root.dump(2)); } void write_lib_cmake(build_env_ref env, @@ -376,8 +381,8 @@ void builder::build(const build_params& params) const { BPT_ERR_REF("test-failure")); } - if (params.emit_lmi) { - write_lmi(env, plan, params.out_root, *params.emit_lmi); + if (params.emit_built_json) { + write_built_json(env, plan, *params.emit_built_json); } if (params.emit_cmake) { diff --git a/src/bpt/build/params.hpp b/src/bpt/build/params.hpp index fe55cc86..3d415f90 100644 --- a/src/bpt/build/params.hpp +++ b/src/bpt/build/params.hpp @@ -10,8 +10,7 @@ namespace bpt { struct build_params { fs::path out_root; - std::optional existing_lm_index; - std::optional emit_lmi; + std::optional emit_built_json; std::optional emit_cmake{}; std::optional tweaks_dir{}; bpt::toolchain toolchain; diff --git a/src/bpt/cli/cmd/build.cpp b/src/bpt/cli/cmd/build.cpp index 37d174f7..5647302d 100644 --- a/src/bpt/cli/cmd/build.cpp +++ b/src/bpt/cli/cmd/build.cpp @@ -13,12 +13,11 @@ namespace bpt::cli::cmd { static int _build(const options& opts) { auto builder = create_project_builder(opts); builder.build({ - .out_root = opts.out_path.value_or(fs::current_path() / "_build"), - .existing_lm_index = opts.build.lm_index, - .emit_lmi = {}, - .tweaks_dir = opts.build.tweaks_dir, - .toolchain = opts.load_toolchain(), - .parallel_jobs = opts.jobs, + .out_root = opts.out_path.value_or(fs::current_path() / "_build"), + .emit_built_json = std::nullopt, + .tweaks_dir = opts.build.tweaks_dir, + .toolchain = opts.load_toolchain(), + .parallel_jobs = opts.jobs, }); return 0; diff --git a/src/bpt/cli/cmd/build_common.cpp b/src/bpt/cli/cmd/build_common.cpp index 0c54e4ea..6c67bb37 100644 --- a/src/bpt/cli/cmd/build_common.cpp +++ b/src/bpt/cli/cmd/build_common.cpp @@ -49,7 +49,7 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { }; builder builder; - if (!opts.build.lm_index.has_value()) { + if (!opts.build.built_json.has_value()) { auto crs_deps = proj_sd.pkg.libraries | std::views::transform(NEO_TL(_1.dependencies)) | std::views::join | neo::to_vector; diff --git a/src/bpt/cli/cmd/build_deps.cpp b/src/bpt/cli/cmd/build_deps.cpp index 7280db07..3c358208 100644 --- a/src/bpt/cli/cmd/build_deps.cpp +++ b/src/bpt/cli/cmd/build_deps.cpp @@ -23,13 +23,12 @@ static int _build_deps(const options& opts) { auto cache = open_ready_cache(opts); bpt::build_params params{ - .out_root = opts.out_path.value_or(fs::current_path() / "_deps"), - .existing_lm_index = {}, - .emit_lmi = opts.build.lm_index.value_or("INDEX.lmi"), - .emit_cmake = opts.build_deps.cmake_file, - .tweaks_dir = opts.build.tweaks_dir, - .toolchain = opts.load_toolchain(), - .parallel_jobs = opts.jobs, + .out_root = opts.out_path.value_or(fs::current_path() / "_deps"), + .emit_built_json = opts.build.built_json.value_or("_built.json"), + .emit_cmake = opts.build_deps.cmake_file, + .tweaks_dir = opts.build.tweaks_dir, + .toolchain = opts.load_toolchain(), + .parallel_jobs = opts.jobs, }; bpt::builder builder; diff --git a/src/bpt/cli/cmd/compile_file.cpp b/src/bpt/cli/cmd/compile_file.cpp index 4fc53c7b..30e228fb 100644 --- a/src/bpt/cli/cmd/compile_file.cpp +++ b/src/bpt/cli/cmd/compile_file.cpp @@ -21,11 +21,10 @@ int _compile_file(const options& opts) { { .out_root = opts.out_path.value_or(fs::current_path() / "_build"), - .existing_lm_index = opts.build.lm_index, - .emit_lmi = {}, - .tweaks_dir = opts.build.tweaks_dir, - .toolchain = opts.load_toolchain(), - .parallel_jobs = opts.jobs, + .emit_built_json = std::nullopt, + .tweaks_dir = opts.build.tweaks_dir, + .toolchain = opts.load_toolchain(), + .parallel_jobs = opts.jobs, }); return 0; }, diff --git a/src/bpt/cli/error_handler.cpp b/src/bpt/cli/error_handler.cpp index 1de4beac..64bdf3e3 100644 --- a/src/bpt/cli/error_handler.cpp +++ b/src/bpt/cli/error_handler.cpp @@ -78,10 +78,14 @@ auto handlers = std::tuple( // bpt_log(error, "Error loading project info from [.bold.yellow[{}]]"_styled, bpt_yaml.value.string()); - bpt_log(error, "Unknown project property '.bold.red[{}]'"_styled, badkey.given); - if (badkey.nearest.has_value()) { - bpt_log(error, " (Did you mean '.bold.green[{}]'?)"_styled, *badkey.nearest); - } + badkey.log_error("Unknown project property '.bold.red[{}]'"_styled); + return 1; + }, + [](e_parse_dependency_manifest_path deps_json, e_bad_deps_json_key badkey) { + bpt_log(error, + "Error loading dependency info from [.bold.yellow[{}]]"_styled, + deps_json.value.string()); + badkey.log_error("Unknown property '.bold.red[{}]'"_styled); return 1; }, [](const semester::walk_error& exc, diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 28c084db..c1bb3c42 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -71,13 +71,6 @@ struct setup { .action = put_into(opts.out_path), }; - argument lm_index_arg{ - .long_spellings = {"libman-index"}, - .help = "Path to a libman index to use", - .valname = "", - .action = put_into(opts.build.lm_index), - }; - argument jobs_arg{ .long_spellings = {"jobs"}, .short_spellings = {"j"}, @@ -215,8 +208,6 @@ struct setup { build_cmd.add_argument(no_warn_arg.dup()); build_cmd.add_argument(out_arg.dup()).help = "Directory where bpt will write build results"; - build_cmd.add_argument(lm_index_arg.dup()).help - = "Path to a libman index file to use for loading project dependencies"; build_cmd.add_argument(jobs_arg.dup()); build_cmd.add_argument(tweaks_dir_arg.dup()); } @@ -227,7 +218,6 @@ struct setup { compile_file_cmd.add_argument(no_warn_arg.dup()).help = "Disable compiler warnings"; compile_file_cmd.add_argument(jobs_arg.dup()).help = "Set the maximum number of files to compile in parallel"; - compile_file_cmd.add_argument(lm_index_arg.dup()); compile_file_cmd.add_argument(out_arg.dup()); compile_file_cmd.add_argument(tweaks_dir_arg.dup()); add_repo_args(compile_file_cmd); @@ -243,8 +233,12 @@ struct setup { build_deps_cmd.add_argument(toolchain_arg.dup()).required; build_deps_cmd.add_argument(jobs_arg.dup()); build_deps_cmd.add_argument(out_arg.dup()); - build_deps_cmd.add_argument(lm_index_arg.dup()).help - = "Destination path for the generated libman index file"; + build_deps_cmd.add_argument({ + .long_spellings = {"built-json"}, + .help = "Destination of the generated '_built.json' file.", + .valname = "", + .action = put_into(opts.build.built_json), + }); add_repo_args(build_deps_cmd); build_deps_cmd.add_argument({ .long_spellings = {"deps-file"}, diff --git a/src/bpt/cli/options.hpp b/src/bpt/cli/options.hpp index 41fbe726..38172ffc 100644 --- a/src/bpt/cli/options.hpp +++ b/src/bpt/cli/options.hpp @@ -143,7 +143,7 @@ struct options { struct { bool want_tests = true; bool want_apps = true; - opt_path lm_index; + opt_path built_json; opt_path tweaks_dir; } build; diff --git a/src/bpt/deps.cpp b/src/bpt/deps.cpp index 25fdd38c..94dc6a4c 100644 --- a/src/bpt/deps.cpp +++ b/src/bpt/deps.cpp @@ -1,12 +1,14 @@ #include "./deps.hpp" #include +#include #include #include using namespace bpt; dependency_manifest dependency_manifest::from_file(path_ref fpath) { + BPT_E_SCOPE(e_parse_dependency_manifest_path{fpath}); auto data = bpt::parse_json5_file(fpath); dependency_manifest ret; @@ -20,6 +22,7 @@ dependency_manifest dependency_manifest::from_file(path_ref fpath) { require_mapping{"The root of a dependency manifest must be a JSON object"}, mapping{ dym.tracker(), + if_key{"$schema", just_accept}, required_key{ "dependencies", "A 'dependencies' key is required", @@ -27,7 +30,7 @@ dependency_manifest dependency_manifest::from_file(path_ref fpath) { for_each{put_into{std::back_inserter(ret.dependencies), project_dependency::from_json_data}}, }, - dym.rejecter(), + dym.rejecter(), }); return ret; diff --git a/src/bpt/deps.hpp b/src/bpt/deps.hpp index 39530925..25ea12d2 100644 --- a/src/bpt/deps.hpp +++ b/src/bpt/deps.hpp @@ -1,10 +1,19 @@ #pragma once +#include #include #include namespace bpt { +struct e_parse_dependency_manifest_path { + fs::path value; +}; + +struct e_bad_deps_json_key : e_nonesuch { + using e_nonesuch::e_nonesuch; +}; + /** * Represents a dependency listing file, which is a subset of a package manifest */ From d24804054022a1038193a9eb3c9a697ebb64adc3 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 14 May 2022 20:06:25 -0600 Subject: [PATCH 35/62] Ensure we stop when move_file fails --- src/bpt/util/fs/shutil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bpt/util/fs/shutil.cpp b/src/bpt/util/fs/shutil.cpp index 88b0a244..b37ce4d1 100644 --- a/src/bpt/util/fs/shutil.cpp +++ b/src/bpt/util/fs/shutil.cpp @@ -54,7 +54,7 @@ result bpt::move_file(path_ref source, path_ref dest) { } if (ec != std::errc::cross_device_link && ec != std::errc::permission_denied) { - BOOST_LEAF_NEW_ERROR(); + return BOOST_LEAF_NEW_ERROR(); } auto tmp = bpt_leaf_try_some { return bpt::temporary_dir::create_in(dest.parent_path()); } From 634f8923459b72c2d07b2d4d3c090d2590c75473 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 15 May 2022 20:00:19 -0600 Subject: [PATCH 36/62] Consume short switch arguments (Fixes '-NDR' handling) --- src/debate/argument_parser.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/debate/argument_parser.cpp b/src/debate/argument_parser.cpp index d4bc224d..5217b0f2 100644 --- a/src/debate/argument_parser.cpp +++ b/src/debate/argument_parser.cpp @@ -240,6 +240,10 @@ struct parse_engine { if (!arg.nargs) { // Just a switch. Consume a single character arg.action("", spelling); + if (tail.empty()) { + // A lone switch + shift(); + } return tail; } else if (arg.nargs == 1) { // Want one value From 4650bbce6991a37c034a161c670b42056405286a Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 15 May 2022 20:01:58 -0600 Subject: [PATCH 37/62] Don't test LMI presence --- tests/test_build_deps.py | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/tests/test_build_deps.py b/tests/test_build_deps.py index e71261d9..21a1eb1f 100644 --- a/tests/test_build_deps.py +++ b/tests/test_build_deps.py @@ -96,9 +96,7 @@ def bd_project(tmp_project: Project) -> Project: def test_cli(bd_test_repo: CRSRepo, bd_project: Project) -> None: bd_project.bpt.build_deps(['foo@1.2.3'], repos=[bd_test_repo.path]) assert bd_project.root.joinpath('_deps/foo@1.2.3~1').is_dir() - assert bd_project.root.joinpath('_deps/_libman/foo.lmp').is_file() - assert bd_project.root.joinpath('_deps/_libman/foo/foo.lml').is_file() - assert bd_project.root.joinpath('INDEX.lmi').is_file() + assert bd_project.root.joinpath('_built.json').is_file() def test_cli_missing(bd_test_repo: CRSRepo, bd_project: Project) -> None: @@ -111,9 +109,7 @@ def test_from_file(bd_test_repo: CRSRepo, bd_project: Project) -> None: bd_project.write('deps.json5', json.dumps({'dependencies': ['foo+0.3.0']})) bd_project.bpt.build_deps(['-d', 'deps.json5'], repos=[bd_test_repo.path]) assert bd_project.root.joinpath('_deps/foo@1.2.3~1').is_dir() - assert bd_project.root.joinpath('_deps/_libman/foo.lmp').is_file() - assert bd_project.root.joinpath('_deps/_libman/foo/foo.lml').is_file() - assert bd_project.root.joinpath('INDEX.lmi').is_file() + assert bd_project.root.joinpath('_built.json').is_file() def test_from_file_missing(bd_project: Project) -> None: @@ -126,9 +122,7 @@ def test_multiple_deps(bd_test_repo: CRSRepo, bd_project: Project) -> None: """build-deps with multiple deps resolves to a single version""" bd_project.bpt.build_deps(['foo@1.2.3', 'foo@1.2.6'], repos=[bd_test_repo.path]) assert bd_project.root.joinpath('_deps/foo@1.2.8~1').is_dir() - assert bd_project.root.joinpath('_deps/_libman/foo.lmp').is_file() - assert bd_project.root.joinpath('_deps/_libman/foo/foo.lml').is_file() - assert bd_project.root.joinpath('INDEX.lmi').is_file() + assert bd_project.root.joinpath('_built.json').is_file() def test_cmake_simple(project_opener: ProjectOpener, bd_test_repo: CRSRepo) -> None: From aa3c095ff3d75bbdc7723cf3f0402313d97478d4 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 25 May 2022 22:16:13 -0600 Subject: [PATCH 38/62] Step back to CRS v0 --- data/simple.crs/pkg.json | 2 +- data/simple2.crs/pkg.json | 2 +- data/simple3.crs/pkg.json | 2 +- data/simple4.crs/pkg.json | 2 +- src/bpt/crs/info/package.cpp | 6 +-- src/bpt/crs/info/package.test.cpp | 86 +++++++++++++++---------------- tests/test_build_deps.py | 4 +- tests/test_pkg.py | 2 +- tests/test_repo/test_repo.py | 6 +-- tools/bpt_ci/testing/repo.py | 2 +- 10 files changed, 57 insertions(+), 57 deletions(-) diff --git a/data/simple.crs/pkg.json b/data/simple.crs/pkg.json index 977ed64a..57b98913 100644 --- a/data/simple.crs/pkg.json +++ b/data/simple.crs/pkg.json @@ -1,5 +1,5 @@ { - "schema-version": 1, + "schema-version": 0, "name": "test-pkg", "version": "1.2.43", "pkg-version": 1, diff --git a/data/simple2.crs/pkg.json b/data/simple2.crs/pkg.json index fb681d80..0aed7dda 100644 --- a/data/simple2.crs/pkg.json +++ b/data/simple2.crs/pkg.json @@ -1,5 +1,5 @@ { - "schema-version": 1, + "schema-version": 0, "name": "test-pkg", "version": "1.3.0", "pkg-version": 1, diff --git a/data/simple3.crs/pkg.json b/data/simple3.crs/pkg.json index eec71f49..c1722209 100644 --- a/data/simple3.crs/pkg.json +++ b/data/simple3.crs/pkg.json @@ -1,5 +1,5 @@ { - "schema-version": 1, + "schema-version": 0, "name": "test-pkg", "version": "1.3.0", "pkg-version": 2, diff --git a/data/simple4.crs/pkg.json b/data/simple4.crs/pkg.json index b1465581..d8bfc33c 100644 --- a/data/simple4.crs/pkg.json +++ b/data/simple4.crs/pkg.json @@ -1,5 +1,5 @@ { - "schema-version": 1, + "schema-version": 0, "name": "test-pkg", "version": "1.3.0", "pkg-version": 3, diff --git a/src/bpt/crs/info/package.cpp b/src/bpt/crs/info/package.cpp index 8353a590..a5194af0 100644 --- a/src/bpt/crs/info/package.cpp +++ b/src/bpt/crs/info/package.cpp @@ -40,8 +40,8 @@ package_info package_info::from_json_data(const json5::data& data) { if (crs_version == data.as_object().cend()) { throw(semester::walk_error{"A 'schema-version' integer is required"}); } - if (!crs_version->second.is_number() || crs_version->second.as_number() != 1) { - throw(semester::walk_error{"Only 'schema-version' == 1 is supported"}); + if (!crs_version->second.is_number() || crs_version->second.as_number() != 0) { + throw(semester::walk_error{"Only 'schema-version' == 0 is supported"}); } return from_json_data_v1(data); } @@ -111,7 +111,7 @@ std::string package_info::to_json(int indent) const noexcept { {"extra", json5_as_nlohmann_json(extra)}, {"meta", json5_as_nlohmann_json(meta)}, {"libraries", std::move(ret_libs)}, - {"schema-version", 1}, + {"schema-version", 0}, }); return indent ? data.dump(indent) : data.dump(); diff --git a/src/bpt/crs/info/package.test.cpp b/src/bpt/crs/info/package.test.cpp index 1d992052..ac6ecdeb 100644 --- a/src/bpt/crs/info/package.test.cpp +++ b/src/bpt/crs/info/package.test.cpp @@ -16,37 +16,37 @@ TEST_CASE("Reject bad meta informations") { {"f", "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while " "parsing value - invalid literal; last read: 'f'"}, - {"{\"schema-version\": 1}", "A string 'name' is required"}, - {R"({"schema-version": 1, "name": "foo"})", "A 'version' string is required"}, - {R"({"schema-version": 1, "name": "foo."})", + {"{\"schema-version\": 0}", "A string 'name' is required"}, + {R"({"schema-version": 0, "name": "foo"})", "A 'version' string is required"}, + {R"({"schema-version": 0, "name": "foo."})", "Invalid name string 'foo.': Names must not end with a punctuation character"}, - {R"({"schema-version": 1, "name": "foo", "version": "bleh"})", + {R"({"schema-version": 0, "name": "foo", "version": "bleh"})", "Invalid semantic version string 'bleh'"}, {R"({ "name": "foo", "version": "1.2.3", - "schema-version": 1 + "schema-version": 0 })", "A 'pkg-version' integer is required"}, {R"({ "name": "foo", "version": "1.2.3", "pkg-version": true, - "schema-version": 1 + "schema-version": 0 })", "'pkg-version' must be an integer"}, {R"({ "name": "foo", "version": "1.2.3", "pkg-version": 3.14, - "schema-version": 1 + "schema-version": 0 })", "'pkg-version' must be an integer"}, {R"({ "name": "foo", "version": "1.2.3", "pkg-version": 1, - "schema-version": 1 + "schema-version": 0 })", "A 'libraries' array is required"}, {R"({ @@ -54,7 +54,7 @@ TEST_CASE("Reject bad meta informations") { "version": "1.2.3", "pkg-version": 1, "libraries": {}, - "schema-version": 1 + "schema-version": 0 })", "'libraries' must be an array of library objects"}, {R"({ @@ -62,7 +62,7 @@ TEST_CASE("Reject bad meta informations") { "version": "1.2.3", "pkg-version": 1, "libraries": [], - "schema-version": 1 + "schema-version": 0 })", "'libraries' array must be non-empty"}, {R"({ @@ -70,7 +70,7 @@ TEST_CASE("Reject bad meta informations") { "version": "1.2.3", "pkg-version": 1, "libraries": [12], - "schema-version": 1 + "schema-version": 0 })", "Each library must be a JSON object"}, {R"({ @@ -78,7 +78,7 @@ TEST_CASE("Reject bad meta informations") { "version": "1.2.3", "pkg-version": 1, "libraries": [{}], - "schema-version": 1 + "schema-version": 0 })", "A library 'name' string is required"}, {R"({ @@ -88,7 +88,7 @@ TEST_CASE("Reject bad meta informations") { "libraries": [{ "name": "foo" }], - "schema-version": 1 + "schema-version": 0 })", "A library 'path' string is required"}, {R"({ @@ -99,7 +99,7 @@ TEST_CASE("Reject bad meta informations") { "name": "foo", "path": 12 }], - "schema-version": 1 + "schema-version": 0 })", "Library 'path' must be a string"}, {R"({ @@ -110,7 +110,7 @@ TEST_CASE("Reject bad meta informations") { "name": "foo", "path": "/foo/bar" }], - "schema-version": 1 + "schema-version": 0 })", "Library path [/foo/bar] must be a relative path"}, {R"({ @@ -121,7 +121,7 @@ TEST_CASE("Reject bad meta informations") { "name": "foo", "path": "../bar" }], - "schema-version": 1 + "schema-version": 0 })", "Library path [../bar] must not reach outside of the distribution directory."}, {R"({ @@ -133,7 +133,7 @@ TEST_CASE("Reject bad meta informations") { "path": ".", "test-using": [] }], - "schema-version": 1 + "schema-version": 0 })", "A 'using' array is required"}, {R"({ @@ -145,7 +145,7 @@ TEST_CASE("Reject bad meta informations") { "path": ".", "using": [] }], - "schema-version": 1 + "schema-version": 0 })", "A 'test-using' array is required"}, {R"({ @@ -158,7 +158,7 @@ TEST_CASE("Reject bad meta informations") { "test-using": [], "using": [] }], - "schema-version": 1 + "schema-version": 0 })", "A 'dependencies' array is required"}, {R"({ @@ -171,7 +171,7 @@ TEST_CASE("Reject bad meta informations") { "using": [], "dependencies": {} }], - "schema-version": 1 + "schema-version": 0 })", "'dependencies' must be an array of dependency objects"}, {R"({ @@ -184,7 +184,7 @@ TEST_CASE("Reject bad meta informations") { "using": [], "dependencies": [12] }], - "schema-version": 1 + "schema-version": 0 })", "Each dependency should be a JSON object"}, {R"({ @@ -199,7 +199,7 @@ TEST_CASE("Reject bad meta informations") { "test-dependencies": [], "dependencies": [{}] }], - "schema-version": 1 + "schema-version": 0 })", "A string 'name' is required for each dependency"}, {R"({ @@ -216,7 +216,7 @@ TEST_CASE("Reject bad meta informations") { "name": "bad-name." }] }], - "schema-version": 1 + "schema-version": 0 })", "Invalid name string 'bad-name.': Names must not end with a punctuation character"}, {R"({ @@ -237,7 +237,7 @@ TEST_CASE("Reject bad meta informations") { "using": ["foo"] }] }], - "schema-version": 1 + "schema-version": 0 })", "A 'test-dependencies' array is required"}, {R"({ @@ -254,7 +254,7 @@ TEST_CASE("Reject bad meta informations") { "name": "bar" }] }], - "schema-version": 1 + "schema-version": 0 })", "A 'versions' array is required for each dependency"}, {R"({ @@ -272,7 +272,7 @@ TEST_CASE("Reject bad meta informations") { "versions": 12 }] }], - "schema-version": 1 + "schema-version": 0 })", "Dependency 'versions' must be an array"}, {R"({ @@ -290,7 +290,7 @@ TEST_CASE("Reject bad meta informations") { "versions": [12] }] }], - "schema-version": 1 + "schema-version": 0 })", "'versions' elements must be objects"}, {R"({ @@ -309,7 +309,7 @@ TEST_CASE("Reject bad meta informations") { "using": [] }] }], - "schema-version": 1 + "schema-version": 0 })", "A dependency's 'versions' array may not be empty"}, {R"({ @@ -327,7 +327,7 @@ TEST_CASE("Reject bad meta informations") { "versions": [{}] }] }], - "schema-version": 1 + "schema-version": 0 })", "'low' version is required"}, {R"({ @@ -347,7 +347,7 @@ TEST_CASE("Reject bad meta informations") { }] }] }], - "schema-version": 1 + "schema-version": 0 })", "'low' version must be a string"}, {R"({ @@ -367,7 +367,7 @@ TEST_CASE("Reject bad meta informations") { }] }] }], - "schema-version": 1 + "schema-version": 0 })", "Invalid semantic version string '1.2.'"}, {R"({ @@ -387,7 +387,7 @@ TEST_CASE("Reject bad meta informations") { }] }] }], - "schema-version": 1 + "schema-version": 0 })", "'high' version is required"}, {R"({ @@ -408,7 +408,7 @@ TEST_CASE("Reject bad meta informations") { }] }] }], - "schema-version": 1 + "schema-version": 0 })", "'high' version must be a string"}, {R"({ @@ -429,7 +429,7 @@ TEST_CASE("Reject bad meta informations") { }] }] }], - "schema-version": 1 + "schema-version": 0 })", "A dependency 'using' key is required"}, {R"({ @@ -451,7 +451,7 @@ TEST_CASE("Reject bad meta informations") { "using": [] }] }], - "schema-version": 1 + "schema-version": 0 })", "'high' version must be strictly greater than 'low' version"}, {R"({ @@ -473,7 +473,7 @@ TEST_CASE("Reject bad meta informations") { "using": [12] }] }], - "schema-version": 1 + "schema-version": 0 })", "Each 'using' item must be a usage string"}, {R"({ @@ -495,7 +495,7 @@ TEST_CASE("Reject bad meta informations") { "using": ["baz/quux"] }] }], - "schema-version": 1 + "schema-version": 0 })", "Invalid name string 'baz/quux'"}, {R"({ @@ -540,7 +540,7 @@ TEST_CASE("Reject bad meta informations") { }], "schema-version": true })", - "Only 'schema-version' == 1 is supported"}, + "Only 'schema-version' == 0 is supported"}, {R"({ "name": "foo", "version": "1.2.3", @@ -560,9 +560,9 @@ TEST_CASE("Reject bad meta informations") { "using": [] }] }], - "schema-version": 1.4 + "schema-version": 0.4 })", - "Only 'schema-version' == 1 is supported"}, + "Only 'schema-version' == 0 is supported"}, {R"({ "name": "foo", "version": "1.2.3", @@ -584,7 +584,7 @@ TEST_CASE("Reject bad meta informations") { }], "schema-version": 3 })", - "Only 'schema-version' == 1 is supported"}, + "Only 'schema-version' == 0 is supported"}, })); INFO("Parsing data: " << given); CAPTURE(expect_error); @@ -626,7 +626,7 @@ TEST_CASE("Check some valid meta JSON") { "test-dependencies": [], "dependencies": [] }], - "schema-version": 1 + "schema-version": 0 })"); REQUIRE_NOTHROW(bpt::crs::package_info::from_json_str(given)); } @@ -659,7 +659,7 @@ TEST_CASE("Check parse results") { }], "test-dependencies": [] }], - "schema-version": 1 + "schema-version": 0 })", pkg_meta{ .id=bpt::crs::pkg_id{ diff --git a/tests/test_build_deps.py b/tests/test_build_deps.py index 21a1eb1f..6bc5e6c8 100644 --- a/tests/test_build_deps.py +++ b/tests/test_build_deps.py @@ -151,7 +151,7 @@ def test_cmake_transitive(bd_project: Project, tmp_crs_repo: CRSRepo, dir_render { 'foo': { 'pkg.json': json.dumps({ - 'schema-version': 1, + 'schema-version': 0, 'name': 'foo', 'version': '1.2.3', 'pkg-version': 1, @@ -177,7 +177,7 @@ def test_cmake_transitive(bd_project: Project, tmp_crs_repo: CRSRepo, dir_render }, 'bar': { 'pkg.json': json.dumps({ - 'schema-version': 1, + 'schema-version': 0, 'name': 'bar', 'version': '1.2.3', 'pkg-version': 1, diff --git a/tests/test_pkg.py b/tests/test_pkg.py index e4a126f0..04f947b7 100644 --- a/tests/test_pkg.py +++ b/tests/test_pkg.py @@ -127,7 +127,7 @@ def test_pkg_create_almost_valid(tmp_project: Project) -> None: }] }], "schema-version": - 1 + 0 } tmp_project.write('pkg.json', json.dumps(pkg_data)) with error.expect_error_marker('invalid-pkg-json'): diff --git a/tests/test_repo/test_repo.py b/tests/test_repo/test_repo.py index d78017fb..490a5507 100644 --- a/tests/test_repo/test_repo.py +++ b/tests/test_repo/test_repo.py @@ -42,7 +42,7 @@ def test_repo_import(bpt: BPTWrapper, tmp_crs_repo: CRSRepo, tmp_project: Projec 'pkg.json', json.dumps({ 'schema-version': - 1, + 0, 'name': 'meow', 'version': @@ -220,7 +220,7 @@ def test_repo_validate_simple(tmp_crs_repo: CRSRepo, tmp_path: Path) -> None: 'pkg-version': 1, 'schema-version': - 1, + 0, 'libraries': [{ 'path': '.', 'name': 'foo', @@ -241,7 +241,7 @@ def test_repo_validate_interdep(tmp_crs_repo: CRSRepo, tmp_path: Path) -> None: 'name': 'foo', 'version': '1.2.3', 'pkg-version': 1, - 'schema-version': 1, + 'schema-version': 0, 'libraries': [{ 'path': '.', 'name': 'foo', diff --git a/tools/bpt_ci/testing/repo.py b/tools/bpt_ci/testing/repo.py index 33b4144f..12a75757 100644 --- a/tools/bpt_ci/testing/repo.py +++ b/tools/bpt_ci/testing/repo.py @@ -100,7 +100,7 @@ def http_crs_repo(tmp_crs_repo: CRSRepo, http_server_factory: HTTPServerFactory) def make_simple_crs(name: str, version: str, *, pkg_version: int = 1) -> Any: return { 'schema-version': - 1, + 0, 'name': name, 'version': From daeef840a0023185f09ebe9ab3d88063579c9e1f Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 25 May 2022 22:16:47 -0600 Subject: [PATCH 39/62] Rename file to match version tweak --- src/bpt/crs/info/{package.walk.v1.cpp => package.walk.v0.cpp} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/bpt/crs/info/{package.walk.v1.cpp => package.walk.v0.cpp} (100%) diff --git a/src/bpt/crs/info/package.walk.v1.cpp b/src/bpt/crs/info/package.walk.v0.cpp similarity index 100% rename from src/bpt/crs/info/package.walk.v1.cpp rename to src/bpt/crs/info/package.walk.v0.cpp From 352b5f58e37dda3e5022f6ff2986dd4734302bc3 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 25 May 2022 22:17:24 -0600 Subject: [PATCH 40/62] Read dependencies file as YAML --- src/bpt/cli/options.cpp | 2 +- src/bpt/deps.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index c1bb3c42..5bb31cca 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -243,7 +243,7 @@ struct setup { build_deps_cmd.add_argument({ .long_spellings = {"deps-file"}, .short_spellings = {"d"}, - .help = "Path to a JSON5 file listing dependencies", + .help = "Path to a YAML file listing dependencies", .valname = "", .can_repeat = true, .action = debate::push_back_onto(opts.build_deps.deps_files), diff --git a/src/bpt/deps.cpp b/src/bpt/deps.cpp index 94dc6a4c..2c39294e 100644 --- a/src/bpt/deps.cpp +++ b/src/bpt/deps.cpp @@ -4,12 +4,14 @@ #include #include #include +#include +#include using namespace bpt; dependency_manifest dependency_manifest::from_file(path_ref fpath) { BPT_E_SCOPE(e_parse_dependency_manifest_path{fpath}); - auto data = bpt::parse_json5_file(fpath); + auto data = bpt::yaml_as_json5_data(bpt::parse_yaml_file(fpath)); dependency_manifest ret; using namespace bpt::walk_utils; From 02f5cacd115d6b77d7f923f95a2d34beddf00a9a Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 25 May 2022 22:18:00 -0600 Subject: [PATCH 41/62] Update docs for build-deps and CMake integration --- docs/crs/index.rst | 2 +- docs/guide/build-deps.rst | 198 ++++++++++------------------------ docs/guide/cli/build-deps.rst | 5 + docs/guide/cmake.rst | 23 ++-- docs/guide/terms.rst | 14 +++ 5 files changed, 88 insertions(+), 154 deletions(-) diff --git a/docs/crs/index.rst b/docs/crs/index.rst index 9106643c..6546be91 100644 --- a/docs/crs/index.rst +++ b/docs/crs/index.rst @@ -102,7 +102,7 @@ The basic interface of ``pkg.json`` looks as below: .. code-block:: javascript interface PKGJSON { - "schema-version": 1, + "schema-version": 0, name: NameString, version: VersionString, "pkg-version": integer, diff --git a/docs/guide/build-deps.rst b/docs/guide/build-deps.rst index 80c597f7..a63bd7ed 100644 --- a/docs/guide/build-deps.rst +++ b/docs/guide/build-deps.rst @@ -1,184 +1,98 @@ Building and Using |bpt| in Another Build System ################################################## -One of |bpt|'s primary goals is to inter-operate with other build systems -cleanly. One of |bpt|'s primary outputs is *libman* package indices. These -package indices can be imported into other build systems that support the -`libman`_ format. (At the time of writing there is a CMake module which can do -the import, but other build systems are planned.) +.. default-role:: term -.. _libman: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/libman/develop/data/spec.bs +One of |bpt|'s primary goals is to inter-operate with other build systems +cleanly. One of |bpt|'s primary outputs is machine-readable `JSON` summary of +its build results. |bpt| also supports emitting a ``include()-able`` CMake_ +module for consumption by older CMake versions that cannot parse the JSON +natively. .. _PMM: https://github.com/vector-of-bool/PMM .. _CMakeCM: https://github.com/vector-of-bool/CMakeCM -.. _lm-cmake: https://raw.githubusercontent.com/vector-of-bool/libman/develop/cmake/libman.cmake +.. _CMake: https://cmake.org +.. _lm-cmake: https://raw.githubusercontent.com/vector-of-bool/libman/develop/cmake/libman.cmake -.. _build-deps.gen-libman: -Generating a libman Index -************************* +Generating a Build for Importing +******************************** -Importing libman packages into a build system requires that we have a libman -index generated on the filesystem. **This index is not generated globally**: It -is generated on a per-build basis as part of the build setup. The index will -describe in build-system-agnostic terms how to include a set of packages and -libraries as part of a build. +In order to import and link against libraries built by |bpt|, one needs to first +run a build and generate the appropriate build results manifest. **This manifest +is not generated globally**: It is generated on a per-build basis as part of the +build process. The manifest will describe in build-system-agnostic terms how to +include and link against as set of libraries generated by a build. |bpt| has first-class support for generating this index. The ``build-deps`` subcommand of |bpt| will download and build a set of dependencies, and places -an ``INDEX.lmi`` file that can be used to import the built results. - - -Declaring Dependencies -====================== - -``bpt build-deps`` accepts a list of dependency statements as command line -arguments, but it may be useful to specify those requirements in a file. - -``bpt build-deps`` accepts a JSON5 file describing the dependencies of a project -as well. This file is similar to a very stripped-down version of a |bpt.yaml|, -and only includes the ``dependencies`` key. (The presence of any other key is an -error.) - -Here is a simple dependencies file that declares a single requirement: - -.. code-block:: js - :caption: ``dependencies.yaml`` - - depends: - - neo-sqlite3^0.2.0 - - -Building Dependencies and the Index -=================================== - -We can invoke ``bpt build-deps`` and give it the path to this file: - -.. code-block:: bash - - $ bpt build-deps --deps-file dependencies.json5 - -When finished, |bpt| will write the build results into a subdirectory called -``_deps`` and generate a file named ``INDEX.lmi``. This file is ready to be -imported into any build system that can understand libman files. - -.. note:: - The output directory and index filepath can be controlled with the - ``--out`` and ``--lmi-path`` flags, respectively. - - -Importing an Index: CMake -************************* - -.. highlight:: cmake +a `JSON` file that can be used to import the built results. .. note:: - This section discusses how to import ``INDEX.lmi`` into CMake, but |bpt| - also has built-in support for generating a CMake targets file. See - :doc:`/howto/cmake` and :doc:`cmake` for even simpler integration steps. + Alternatively, for CMake projects, one can use the + :option:`--cmake ` option to write a CMake script that + defines the needed ``IMPORTED`` targets. Refer: :doc:`cmake` -Supposed that we've generated a libman index and set of packages, and we want to -import them into CMake. CMake doesn't know how to do this natively, but there -exists a single-file module for CMake that allows CMake to import libraries from -libman indices without any additional work. +The :doc:`build-deps ` command accepts a list of +`dependency specifiers ` as positional +`command-line arguments`. |bpt| will attempt to generate a dependency solution +using that set of dependencies and will then obtain and build their sources. -The module is not shipped with CMake, but is available online as a single -stand-alone file. The `libman.cmake `_ file can be downloaded and -added to a project directly, or it can be obtained automatically through a -CMake tool like `PMM`_ (recommended). - -Getting ``libman.cmake`` via PMM +Declaring Dependencies in a File ================================ -Refer to the ``README.md`` file in `the PMM repo `_ for information on how -to get PMM into your CMake project. In short, download and place the -``pmm.cmake`` file in your repository, and ``include()`` the file near the top -of your ``CMakeLists.txt``:: - - include(pmm.cmake) - -Once it has been included, you can call the ``pmm()`` function. To obtain -*libman*, we need to start by enabling `CMakeCM`_:: - - pmm(CMakeCM ROLLING) - -.. warning:: - It is not recommended to use the ``ROLLING`` mode, but it is the easiest to - use when getting started. For reproducible and reliable builds, you should - pin your CMakeCM version using the ``FROM `` argument. +``bpt build-deps`` accepts a list of +`dependency specifiers ` as command line arguments, but it +may be useful to specify those requirements in a file. -Enabling CMakeCM will make available all of the CMake modules available in `the -CMakeCM repository `_, which includes `libman.cmake `_. +``bpt build-deps`` accepts a YAML file describing the dependencies of a project +as well. The only required property in the file is the ``dependencies`` key. +(The presence of any other key is an error.) -After the call to ``pmm()``, simply ``include()`` the ``libman`` module:: - - include(libman) - -That's it! The only function from the module that we will care about for now -is the ``import_packages()`` function. - - -Importing Our Dependencies' Packages -==================================== +Here is a simple dependencies file that declares a single requirement: -To import a package from a libman tree, we need only know the *name* of the -package we wish to import. In our example case above, we depend on -``neo-sqlite3``, so we simply call the libman-CMake function -``import_packages()`` with that package name:: +.. code-block:: yaml + :caption: ``dependencies.yaml`` - import_packages("neo-sqlite3") + dependencies: [ + 'neo-sqlite3^0.2.0' + ] -You'll note that we don't request any particular version of the package: All -versioning resolution is handled by |bpt|. You'll also note that we don't -need to specify our transitive dependencies: This is handled by the libman -index that was generated by |bpt|: It will automatically ``import_packages()`` -any of the transitive dependencies required. +.. seealso:: -More than one package name can be provided to a single call to -``import_packages()``, and ``import_packages()`` may be called multiple times -within a CMake project. + The :yaml:`dependencies` array is an array of `dependency specifier` strings, + the same as those that would be used in a |bpt.yaml| project file. -Using Our Dependencies' Libraries -================================= +Building Dependencies and the Manifest +====================================== -Like with |bpt|, CMake wants us to explicitly declare how our build targets -*use* other libraries. When we import a package from a libman index, the -import will generate CMake ``IMPORTED`` targets that can be linked against. +We can invoke ``bpt build-deps`` and give it the path to this file: -In |bpt| and in libman, a library is identified by a combination of -*namespace* and *name*, joined together with a slash ``/`` character. This -*qualified name* of a library is decided by the original package author, and -should be documented. In the case of ``neo-sqlite3``, the only library is -``neo/sqlite3``. +.. code-block:: bash -When the libman CMake module imports a library, it creates a qualified name -using a double-colon "``::``" instead of a slash. As such, our ``neo/sqlite3`` -is imported in CMake as ``neo::sqlite3``. We can link against it as we would -with any other target:: + $ bpt build-deps --deps-file dependencies.yaml - add_executable(my-application app.cpp) - target_link_libraries(my-application PRIVATE neo::sqlite3) +When finished, |bpt| will write the build results into a subdirectory called +``_deps`` and generate a file named ``_built.json``. This file is ready to be +imported into any build system that can understand its simple schema. -Altogether, here is the final CMake file: +.. note:: -.. code-block:: - :caption: ``CMakeLists.txt`` - :linenos: + The output directory and manifest filepath can be controlled with the + :option:`--out ` and + :option:`--built-json ` flags, respectively. - cmake_minimum_required(VERSION 3.15) - project(MyApplication VERSION 1.0.0) - include(pmm.cmake) - pmm(CMakeCM ROLLING) +CMake Integration +***************** - include(libman) - import_packages("neo-sqlite3") +.. seealso:: - add_executable(my-application app.cpp) - target_link_libraries(my-application PRIVATE neo::sqlite3) + Using |bpt| libraries in CMake is a significant enough use case to warrant a + dedicated page. Refer: :doc:`cmake` diff --git a/docs/guide/cli/build-deps.rst b/docs/guide/cli/build-deps.rst index 0af15f07..cc3cad35 100644 --- a/docs/guide/cli/build-deps.rst +++ b/docs/guide/cli/build-deps.rst @@ -15,6 +15,11 @@ in another project. .. include:: ./opt-tweaks-dir.rst .. include:: ./opt-out.rst +.. option:: --built-json + + Specify the destination :term:`filepath` of the generated ``_built.json`` + file (Refer: :doc:`/guide/build-deps`) + .. option:: --cmake Generate a CMake script that will create imported targets for the diff --git a/docs/guide/cmake.rst b/docs/guide/cmake.rst index fe496ef8..331040e9 100644 --- a/docs/guide/cmake.rst +++ b/docs/guide/cmake.rst @@ -1,17 +1,18 @@ .. highlight:: cmake Using |bpt| in a CMake Project -################################ +############################## + +.. default-role:: term One of |bpt|'s primary goals is to inter-operate with other build systems -cleanly. Because of CMakes ubiquity, |bpt| includes built-in support for -emitting files that can be imported into CMake. +cleanly. Because of `CMakes ` ubiquity, |bpt| includes built-in support +for emitting files that can be imported into CMake. .. seealso:: - Before reading this page, be sure to read the :ref:`build-deps.gen-libman` - section of the :doc:`build-deps` page, which will discuss how to use the - ``bpt build-deps`` subcommand. + Before reading this page, be sure to read the :doc:`build-deps` page, which + will discuss how to use the ``bpt build-deps`` subcommand. .. seealso:: @@ -25,9 +26,9 @@ emitting files that can be imported into CMake. Generating a CMake Import File ****************************** -``build-deps`` accepts an ``--lmi-path`` argument, but also accepts a -``--cmake=`` argument that serves a similar purpose: It will write a CMake -file to ```` that can be ``include()``'d into a CMake project: +``build-deps`` accepts an ``--built-json`` argument, but also accepts a +``--cmake=`` argument that serves a similar purpose: It will write a +`CMake` file to ```` that can be ``include()``'d into a CMake project: .. code-block:: bash @@ -41,7 +42,7 @@ targets. Using the CMake Import File =========================== -Once we have generated the CMake import file using ``bpt build-deps``, we can +Once we have generated the `CMake` import file using ``bpt build-deps``, we can simply import it in our ``CMakeLists.txt``:: include(deps.cmake) @@ -71,7 +72,7 @@ with any other target:: ************************ `PMM`_ is the *package package manager*, and can be used to control and access -package managers from within CMake scripts. This includes controlling |bpt|. +package managers from within `CMake` scripts. This includes controlling |bpt|. With PMM, we can automate all of the previous steps into a single line. For a complete rundown on using PMM to get dependencies via |bpt|, refer to diff --git a/docs/guide/terms.rst b/docs/guide/terms.rst index e74e8a47..ab550d2d 100644 --- a/docs/guide/terms.rst +++ b/docs/guide/terms.rst @@ -286,3 +286,17 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. to use from the external `package`. .. seealso:: :ref:`dep-spec` + + CMake + + **CMake** is a popular cross-platform build system and project configuration + tool for C and C++ projects. + + .. seealso:: + + - |bpt| has support for integrating with CMake + + - :doc:`/guide/cmake` + - :doc:`/howto/cmake` + + - `The CMake homepage `_ From 7a9df83ccd193707767a9bd68eaded1124f2226b Mon Sep 17 00:00:00 2001 From: Max Truxa Date: Mon, 16 May 2022 16:12:21 +0000 Subject: [PATCH 42/62] Abort sdist archive creation if target is a directory --- src/bpt/sdist/dist.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bpt/sdist/dist.cpp b/src/bpt/sdist/dist.cpp index c0ba7c42..998116d9 100644 --- a/src/bpt/sdist/dist.cpp +++ b/src/bpt/sdist/dist.cpp @@ -90,6 +90,10 @@ void bpt::create_sdist_targz(path_ref filepath, const sdist_params& params) { throw_user_error("Destination path '{}' already exists", filepath.string()); } + if (fs::is_directory(filepath)) { + throw_user_error("Destination path '{}' is a directory", + filepath.string()); + } } auto tempdir = temporary_dir::create(); From d1fee98c15dbbff027ae6baf13d9b4c443ebf1da Mon Sep 17 00:00:00 2001 From: Max Truxa Date: Tue, 31 May 2022 09:52:55 +0000 Subject: [PATCH 43/62] Actually create temporary directories on *nix `mktemp` doesn't actually create the directory and is pretty broken on some platforms. `mkdtemp`, `mkstemp` and friends are here to fix this. --- src/bpt/temp.nix.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/bpt/temp.nix.cpp b/src/bpt/temp.nix.cpp index 3969c11c..15d7fb18 100644 --- a/src/bpt/temp.nix.cpp +++ b/src/bpt/temp.nix.cpp @@ -1,13 +1,18 @@ #include "./temp.hpp" #ifndef _WIN32 + +#ifdef __APPLE__ +#include +#endif + using namespace bpt; temporary_dir temporary_dir::create_in(path_ref base) { - auto file = (base / "bpt-tmp-XXXXXX").string(); - - const char* tempdir_path = ::mktemp(file.data()); + fs::create_directories(base); + auto file = (base / "bpt-tmp-XXXXXX").string(); + const char* tempdir_path = ::mkdtemp(file.data()); if (tempdir_path == nullptr) { throw std::system_error(std::error_code(errno, std::system_category()), "Failed to create a temporary directory"); @@ -15,4 +20,5 @@ temporary_dir temporary_dir::create_in(path_ref base) { auto path = fs::path(tempdir_path); return std::make_shared(std::move(path)); } + #endif From 2a94458f4575e73e0d8493038298daa8322f25e8 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 16 Jun 2022 21:39:56 -0600 Subject: [PATCH 44/62] Many docs updates. New Sphinx domain for JSON-ish configs --- docs/conf.py | 340 +++++++++++++++++++- docs/crs/index.rst | 233 +------------- docs/crs/json.rst | 297 +++++++++++++++++ docs/crs/packages.rst | 18 +- docs/guide/libraries.rst | 183 +++++++---- docs/guide/projects.rst | 106 +++--- docs/guide/terms.rst | 12 +- docs/guide/toolchains.rst | 660 +++++++++++++++++++++++--------------- docs/prolog.rst | 7 +- 9 files changed, 1215 insertions(+), 641 deletions(-) create mode 100644 docs/crs/json.rst diff --git a/docs/conf.py b/docs/conf.py index e76972fc..78fe1d9a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,13 +1,28 @@ # -*- coding: utf-8 -*- # Refer: http://www.sphinx-doc.org/en/master/config +from __future__ import annotations from sphinx.application import Sphinx from pathlib import Path -from typing import Any +from typing import Any, ClassVar, Iterator, Literal, NamedTuple, NewType, Sequence, TypedDict, cast, Iterable import sys +import re import hoverxref.extension +from sphinx.domains import Domain, ObjType +from sphinx.directives import ObjectDescription +from docutils.parsers.rst.directives import flag +from sphinx.roles import XRefRole +from sphinx.util.docutils import SphinxRole +from sphinx import addnodes +from sphinx.util.docfields import Field, GroupedField +from sphinx.util.nodes import make_refnode +from docutils import nodes +from docutils.nodes import Element, emphasis +from sphinx.util.typing import OptionSpec +from sphinx.environment import BuildEnvironment +from sphinx.builders import Builder from sphinx.util.fileutil import copy_asset # -- Project information ----------------------------------------------------- @@ -37,6 +52,7 @@ 'pytest': ('https://docs.pytest.org/en/latest/', None), } nitpicky = True +add_function_parenthesis = False if sys.version_info < (3, 10): # Sphinx in older Python fails to handle many typing annotations @@ -54,6 +70,8 @@ 'ref': 'tooltip', 'envvar': 'tooltip', 'option': 'tooltip', + 'schematic:prop': 'tooltip', + 'prop': 'tooltip', } hoverxref_roles = list(hoverxref_role_types.keys()) @@ -72,6 +90,325 @@ def intercept_copy_asset(path: str, dest: str, context: Any) -> None: hoverxref.extension.copy_asset = intercept_copy_asset +_PARENT_KEY = 'schematic:DOTPATH' + +_FullNameStr = NewType('_FullName', str) +_Ident = NewType("_Ident", str) + + +def _fullname(env: BuildEnvironment, name: str) -> _FullNameStr: + if '.' in name: + return _FullNameStr(name) + + par: Sequence[str] = env.ref_context.get(_PARENT_KEY, []) + if par: + return _FullNameStr('.'.join(par) + '.' + name) + return _FullNameStr(name) + + +def _shortname(fn: _FullNameStr) -> str: + d = fn.split('.') + return d[-1] + + +def _makeid(env: BuildEnvironment, objtype: str, name: _FullNameStr) -> _Ident: + return _Ident(f'sch-{objtype}-{name}') + + +def _dotpath(env: BuildEnvironment) -> Sequence[str]: + return tuple(env.ref_context.setdefault(_PARENT_KEY, [])) + + +class _SchematicEntry(TypedDict): + parent: Sequence[str] + shortname: str + docname: str + node_id: _Ident + objtype: Literal['property', 'mapping'] + + +class _SchematicInventory(TypedDict): + objects: dict[str, _SchematicEntry] + + +class SchematicObject(ObjectDescription[tuple[_FullNameStr, _Ident]]): + + has_content = True + required_arguments = 1 + optional_arguments = 0 + final_argument_whitespace = False + option_spec: OptionSpec = {} + obj_type_label: ClassVar[str] + + def add_target_and_index(self, name: tuple[_FullNameStr, _Ident], sig: str, signode: addnodes.desc_signature): + # assert 0, f'Updating inventory {ident=} {self.state.document=}' + fullname, ident = name + shortname = _shortname(fullname) + if ident not in self.state.document.ids: + signode['names'].append(ident) + signode['ids'].append(ident) + self.state.document.note_explicit_target(signode) + + dom = cast(SchematicDomain, self.env.get_domain('schematic')) + print(f'Saving {self.objtype} {fullname}') + assert self.objtype in ('property', 'mapping') + dom.data['objects'][fullname] = { + 'parent': _dotpath(self.env), + 'shortname': _shortname(fullname), + 'docname': self.env.docname, + 'node_id': ident, + 'objtype': self.objtype, + } + # dom.objects + entry = ('pair', f'{self.objtype} ; {shortname}', ident, 'main', None) + self.indexnode['entries'].append(entry) # type: ignore + + def handle_signature(self, sig: str, signode: addnodes.desc_signature) -> tuple[_FullNameStr, _Ident]: + signode += addnodes.desc_annotation('', '', *self.signature_prefix(), addnodes.desc_sig_space()) + signode += addnodes.desc_name(sig, sig) + suffix = tuple(self.signature_suffix()) + if suffix: + signode += addnodes.desc_sig_space() + signode += suffix + fn = _fullname(self.env, sig) + id = _makeid(self.env, self.objtype, fn) + return fn, id + + def signature_prefix(self) -> 'Iterable[Element]': + return [addnodes.desc_sig_keyword(self.objtype, self.objtype)] + + def signature_suffix(self) -> 'Iterable[Element]': + return [] + + def before_content(self): + name: str = self.arguments[0].strip() + self.env.ref_context.setdefault(_PARENT_KEY, []).append(name) + + def after_content(self) -> None: + self.env.ref_context[_PARENT_KEY].pop() + return super().after_content() + + +class SchematicMapping(SchematicObject): + pass + + +class _PropertyBaseType(NamedTuple): + spelling: str + + def nodes(self, env: BuildEnvironment) -> Iterator[nodes.Node]: + if self.spelling in ('undefined', 'number', 'integer', 'null', 'string', 'boolean', 'unknown'): + yield nodes.Text(self.spelling) + else: + ref = addnodes.pending_xref('', + nodes.Text(self.spelling), + reftarget=self.spelling, + reftype='mapping', + refdomain='schematic') + ref[_PARENT_KEY] = _dotpath(env) + yield ref + + +class _PropertyDottedType(NamedTuple): + parent: _PropertyBaseType | _PropertyDottedType + part: str + + def nodes(self, env: BuildEnvironment) -> Iterator[nodes.Node]: + yield from self.parent.nodes(env) + yield nodes.Text(self.part) + + +class _PropertyArrayType(NamedTuple): + type: _PropertyUnionType | _PropertyBaseType | _PropertyDottedType | _PropertyArrayType + + def nodes(self, env: BuildEnvironment) -> Iterator[nodes.Node]: + yield from self.type.nodes(env) + yield nodes.Text('[]') + + +class _PropertyUnionType(NamedTuple): + alternatives: Sequence[_PropertyBaseType | _PropertyArrayType | _PropertyDottedType] + + def nodes(self, env: BuildEnvironment) -> Iterator[nodes.Node]: + yield nodes.Text('(') + it = iter(self.alternatives) + cur = next(it) + while cur is not None: + yield from cur.nodes(env) + cur = next(it, None) + if cur: + yield nodes.Text(' | ') + yield nodes.Text(')') + + +def _parse_dotted_type(spell: str) -> tuple[_PropertyDottedType | _PropertyBaseType, str]: + spell = spell.strip() + mat = re.match(r'([\w\$]+)(.*)', spell) + if not mat: + raise ValueError(f'Invalid type string "{spell}"') + base, tail = mat.groups() + typ = _PropertyBaseType(base) + while mat := re.match(r'\.([\w\$]+)(.*)', tail): + n, tail = mat.groups() + typ = _PropertyDottedType(typ, n) + return typ, tail + + +def _parse_union_alt( + spell: str) -> tuple[_PropertyBaseType | _PropertyDottedType | _PropertyArrayType | _PropertyUnionType, str]: + spell = spell.strip() + if spell.startswith('('): + inner = spell[1:] + typ, tail = _parse_type_str(inner) + if not tail.startswith(')'): + raise ValueError(f'Unclosed parenthesis in type string "{spell}"') + tail = tail[1:].strip() + else: + typ, tail = _parse_dotted_type(spell) + while tail.startswith('[]'): + typ = _PropertyArrayType(typ) + tail = tail[2:].strip() + return typ, tail + + +def _parse_type_str( + spell: str) -> tuple[_PropertyBaseType | _PropertyUnionType | _PropertyArrayType | _PropertyDottedType, str]: + typ, tail = _parse_union_alt(spell) + tail = tail.strip() + if not tail: + return typ, tail + + alts: list[_PropertyBaseType | _PropertyArrayType | _PropertyDottedType] = [] + if isinstance(typ, _PropertyUnionType): + alts.extend(typ.alternatives) + else: + alts.append(typ) + while tail.startswith('|'): + tail = tail[1:].strip() + n, tail = _parse_union_alt(tail) + if isinstance(n, _PropertyUnionType): + alts.extend(n.alternatives) + else: + alts.append(n) + tail = tail.strip() + return _PropertyUnionType(tuple(alts)), tail + + +def parse_type_str(spell: str) -> _PropertyBaseType | _PropertyUnionType | _PropertyArrayType | _PropertyDottedType: + typ, tail = _parse_type_str(spell) + if tail: + raise ValueError(f'Invalid trailing content "{tail}" in type string "{spell}"') + return typ + + +class SchematicProperty(SchematicObject): + option_spec: OptionSpec = { + 'required': flag, + 'optional': flag, + } + + doc_field_types = [ + Field('type', ('type', ), label='Type', has_arg=False, bodyrolename='type'), + GroupedField('option', ('option', ), label='Options', rolename='literal'), + GroupedField('placeholder', ('placeholder', ), label='Placeholders', rolename='literal'), + ] + + # optional_arguments = 500 + + def signature_suffix(self): + r: list[Element] = [] + if 'required' in self.options: + r.append(emphasis('', '(required)')) + if 'optional' in self.options: + r.append(emphasis('', '(optional)')) + return r + + +class SchematicXRefRole(XRefRole): + + def process_link(self, env: "BuildEnvironment", refnode: Element, has_explicit_title: bool, title: str, + target: str) -> tuple[str, str]: + refnode[_PARENT_KEY] = _dotpath(env) + if not has_explicit_title: + if title.startswith('~'): + target = title[1:] + last_dot = title.rfind('.') + if last_dot >= 0: + title = title[last_dot + 1:] + return super().process_link(env, refnode, has_explicit_title, title, target) + + +class SchematicTypeRole(SphinxRole): + + def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]: + t = parse_type_str(self.text) + return [nodes.literal('', '', *(t.nodes(self.env)))], [] + + +class _LiteralRole(SphinxRole): + + def run(self) -> tuple[list[nodes.Node], list[nodes.system_message]]: + return [nodes.literal('', self.text)], [] + + +class SchematicDomain(Domain): + """Domain for JSON/YAML/config schema""" + name = 'schematic' + label = 'Schematic' + object_types = { + 'mapping': ObjType('mapping', 'mapping'), + 'property': ObjType('property', 'prop'), + } + directives = { + 'mapping': SchematicMapping, + 'property': SchematicProperty, + } + roles = { + 'mapping': SchematicXRefRole(), + 'prop': SchematicXRefRole(), + 'type': SchematicTypeRole(), + 'literal': _LiteralRole(), + } + initial_data = { + 'objects': {}, + } + + def __init__(self, *args: Any, **kwargs: Any) -> None: + self.data: _SchematicInventory + super().__init__(*args, **kwargs) + + def merge_domaindata(self, docnames: list[str], otherdata: _SchematicInventory) -> None: + for k, e in otherdata['objects'].items(): + self.data['objects'][k] = e + + def find_obj(self, node: addnodes.pending_xref, name: str) -> _SchematicEntry | None: + if '.' in name: + return self.data['objects'].get(name) + + paths: Sequence[str] = node.get(_PARENT_KEY, []) + if paths: + partials = reversed(['.'.join(paths[:i]) for i in range(len(paths))]) + else: + partials = [name] + for cand in partials: + print('Looking for fullnamed object:', cand) + found = self.data['objects'].get(cand) + if found is not None: + return found + + return self.data['objects'].get(name) + + def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, typ: Literal['mapping', 'prop'], + target: str, node: addnodes.pending_xref, contnode: Element): + ident = f'{typ}:{target}' + ent: _SchematicEntry | None + ent = self.find_obj(node, target) + if ent is None: + raise RuntimeError(f'No such {typ} "{target}"') + # assert , f'{ident=} {self.data=}' + return make_refnode(builder, fromdocname, ent['docname'], ent['node_id'], contnode, target) + + rst_prolog = r''' .. include:: /prolog.rst ''' @@ -79,3 +416,4 @@ def intercept_copy_asset(path: str, dest: str, context: Any) -> None: def setup(app: Sphinx): app.add_css_file('styles.css') + app.add_domain(SchematicDomain) diff --git a/docs/crs/index.rst b/docs/crs/index.rst index 6546be91..d7a7d98f 100644 --- a/docs/crs/index.rst +++ b/docs/crs/index.rst @@ -21,6 +21,12 @@ before being given to a compiler. The `CRS` format is intended to be portable and not directly tied to |bpt| itself. +.. note:: + + This documentation, and `CRS` itself, are both still works-in-progress. It + may be incomplete and feature errors in speling and grammars. + + Topics ###### @@ -31,6 +37,8 @@ Topics dependencies versions names + json + Base Concepts ############# @@ -76,236 +84,11 @@ Briefly, `CRS` concerns itself with the following high-level concepts: :doc:`The documentation page about dependencies ` -Storage Format -############## - -A CRS package can be represented in any system that allows heirarchical data -storage with named files and directories. This may be a regular directory on -disk, a Zip archive, a Tar archive, a database table, or even something as -simple as a single large `JSON` document. - - -.. _pkg.json: - -``pkg.json`` -************ - -At the root of the package must be a valid `JSON` document named ``pkg.json``. -This file encodes all of the metadata in the package. - -At any point in the `JSON` object, if any `JSON` object key string begins with -the substring "``_comment``", then content of that object entry is to be ignored -for validating the `JSON` data. - -The basic interface of ``pkg.json`` looks as below: - -.. code-block:: javascript - - interface PKGJSON { - "schema-version": 0, - name: NameString, - version: VersionString, - "pkg-version": integer, - libraries: CRSLibrary[], - meta?: { - [key: string]: unknown - }, - extra?: null | { - [key: string]: unknown - }, - } - - interface CRSLibrary { - name: NameString, - path: string, - using: NameString[], - dependencies: CRSDependency[], - "test-dependencies": CRSDependency[], - } - - interface CRSDependency { - name: NameString, - using: NameString, - versions: VersionRange[], - } - - interface VersionRange { - low: VersionString, - high: VersionString, - } - -Where "``NameString``" is a string that is a valid :doc:`CRS name ` and -"``VersionString``" is a string that is a valid -:hoverxref:`Semantic Version string `. - -The root of this JSON data must be a JSON object with the following *required* -keys: - -``schema-version`` -================== - -An integer encoding the version of the CRS metadata itself. For this -documentation, this number must be ``1``. - -If the ``schema-version`` is greater than the version supported by the system, -the package must be rejected as invalid. - -``name`` -======== - -A string. Specifies the name of a package. :doc:`Must be a valid name. ` - -``version`` -=========== - -A string. Specifies the version of the package. Must be a valid -:hoverxref:`Semantic Version string `. - -``pkg-version`` -=============== - -An integer. Specifies the version of the package itself (not related to the -version of the software that is packaged). - -If the ``pkg-version`` is not a positive non-zero whole integer, the package is -invalid. - -``libraries`` -============= - -An array of library definitions for the package. Refer to: :ref:`crs.libraries`. -If any of the libraries in the array are invalid, the entire package is invalid. - -``meta`` -======== - -An optional JSON object containing metadata attributes for the package intended -for human consumption. - -``extra`` -========= - -An optional JSON object or ``null`` that encodes additional tool-specific -attributes for the package. - -.. _crs.libraries: - -Libraries -********* - -In |pkg.json|, the ``libraries`` property must be an array of CRS library JSON -objects. - -Each object in that array defines a library for the package. Each object must -contain the following properties: - - -``name`` -======== - -The name of the library. :doc:`Must be a valid name. ` - -No two libraries within a single package may share a name. - - -``path`` -======== - -The path to the library root. This must be a valid UTF-8 POSIX-style relative -filepath using forward-slash "``/``" (solidus) directory separators. The path -may not contain any backslash "``\``" characters. - -A library path must be normalized and validated according to the following -rules: - -1. If the first character in the path is a forward-slash, the path is invalid - (absolute paths are not allowed). -2. For every sequence of two or more forward-slashes in the path string, replace - the sequence with a single forward-slash. -3. Remove a final forward-slash in the path string, if present. -4. Split the path string on forward-slashes into a list of *component* strings. -5. Remove every component from the array that is a single ASCII dot "``.``". -6. For each *component* in the path string that is a dot-dot "``..``": - - 1. If the dot-dot component is the first component in the component list, the - path is invalid (The path attempts to reach outside of the CRS package). - 2. Delete the dot-dot component and the component preceeding it in the array. - -7. All remaining path components must also be valid :doc:`CRS names `, except - that they may begin with an ASCII digit. Otherwise the path is invalid. -8. Join the component array with forward-slashes in-between each component. This - is the new path. -9. If the path is an empty string, the path is "``.``". - -After normalizing the library's path, no two libraries may have the same path. -Some platforms may place additional restrictions on library paths. - - -``using`` -========= - -A list of :doc:`names` of other libraries within the same package. Each string must -correspond to the ``name`` property on some other library in the package. A -library cannot "use" itself. The chain of ``using`` should form a acyclic graph. -If a ``using`` string names a non-existent library, or if there is a cycle in -the ``using`` graph, the entire package is invalid. - - -``dependencies`` -================ - -An array of `CRS dependency` objects. - -This array specifies the dependencies of the library within the package. - - -``test-dependencies`` -===================== - -An array of `CRS dependency` objects. - -This array specifies the test-only dependencies of the library within the -package. Dependencies ************ -A CRS dependency identifies a package by name, one or more version ranges, and -some set of used-libraries. A dependency is associated with a -`library ` within a package, and not with the package as a whole. - -A CRS dependency is specified as a JSON object with the following required -properties: - - -``name`` -======== - -The name of a package which is being depended-upon. -:doc:`Must be a valid name. ` - - -``using`` -========= - -An array of |name| strings identifying libraries within the depended-upon -package to be used by the library that contains this dependency. - - -``versions`` -============ - -An array of one or more *version range* objects. Each JSON object must contain -the following properties: - -``low`` - The minimum version of the range. Must be a valid - :hoverxref:`Semantic Version string `. - -``high`` - The maximum version of the range, exclusive. Must be a valid - :hoverxref:`Semantic Version string `. Range Semantics diff --git a/docs/crs/json.rst b/docs/crs/json.rst new file mode 100644 index 00000000..a0bc87b3 --- /dev/null +++ b/docs/crs/json.rst @@ -0,0 +1,297 @@ +CRS Package Storage +################### + +.. |name| replace:: :doc:`name ` + +A CRS package can be represented in any system that allows heirarchical data +storage with named files and directories. This may be a regular directory on +disk, a Zip archive, a Tar archive, a database table, or even something as +simple as a single large `JSON` document. + + +.. _pkg.json: + +``pkg.json`` +************ + +At the root of the package must be a valid `JSON` document named ``pkg.json``. +This file encodes all of the metadata in the package. + +At any point in the `JSON` object, if any `JSON` object key string begins with +the substring "``_comment``", then content of that object entry is to be ignored +for validating the `JSON` data. + +The basic interface of ``pkg.json`` looks as below: + +.. code-block:: javascript + + interface CRSPackage { + $schema?: string, + "schema-version": 0, + name: NameString, + version: VersionString, + "pkg-version": integer, + libraries: CRSLibrary[], + meta?: { + [key: string]: unknown + }, + extra?: null | { + [key: string]: unknown + }, + } + + interface CRSLibrary { + name: NameString, + path: string, + using: NameString[], + dependencies: CRSDependency[], + "test-dependencies": CRSDependency[], + } + + interface CRSDependency { + name: NameString, + using: NameString, + versions: VersionRange[], + } + + interface VersionRange { + low: VersionString, + high: VersionString, + } + +Where "``NameString``" is a string that is a valid :doc:`CRS name ` and +"``VersionString``" is a string that is a valid +:hoverxref:`Semantic Version string `. + + +.. default-domain:: js + +.. _crs.package: + +Schema +****** + +.. default-domain:: schematic + +.. mapping:: CRSPackage_v0 + + A JSON object type. Any properties that allow :ts:`undefined` are optional, + and all others are required. + + .. property:: schema-version + :required: + + :type: Literal :ts:`0` (zero) + + The version of the `CRS` schema described by the object. For this type at + this version, the value is literal zero :ts:`0`. + + Package processors should validate the content of this property before + checking any other content in the document. + + .. property:: name + :required: + + :type: string + + The name of the package. Must be a valid :doc:`CRS name `. + + .. property:: version + :required: + + :type: string + + The version of the software that is contained in the enclosing package. Must + be a valid :ref:`semver` version string. + + .. note:: Do not confuse with the :schematic:prop:`pkg-version` property. + + .. property:: pkg-version + :required: + + :type: integer + + Used to record revisions of the package itself. This is used when the + content of the package's metadata may require changing, but the content of + the packaged software is equivalent to the content of prior revisions. Must + be greater or equal to :ts:`1` (one). + + .. property:: libraries + :required: + + :type: CRSLibrary_v0[] + + Libraries of the package. Must be a non-empty array of + :schematic:mapping:`CRSLibrary_v0` objects. + + .. property:: meta + + :type: undefined | null | unknown | null + + Used to attach metadata to the package that isn't required for dependency + resolution nor build systems. Package processors should not mandate any + content in the nested ``meta`` object. + + .. property:: extra + :optional: + + :type: undefined | null + + An optional JSON object or ``null`` that encodes additional tool-specific + attributes for the package. + + .. property:: $schema + :optional: + + :type: :ts:`string | undefined` + + A property using by JSON-schema validators. Do not parse nor validate this. + + .. property:: _comment + :optional: + + :type: :ts:`string | undefined` + + Ignore these + + +.. mapping:: CRSLibrary_v0 + + An object type that contains properties of CRS libraries + + +.. default-domain:: js + +.. _crs.libraries: + +Libraries +********* + +In |pkg.json|, the ``libraries`` property must be an array of CRS library JSON +objects. + +Each object in that array defines a library for the package. Each object must +contain the following properties: + + +``name`` +======== + +The name of the library. :doc:`Must be a valid name. ` + +No two libraries within a single package may share a name. + + +``path`` +======== + +The path to the library root. This must be a valid UTF-8 POSIX-style relative +filepath using forward-slash "``/``" (solidus) directory separators. The path +may not contain any backslash "``\``" characters. + +A library path must be normalized and validated according to the following +rules: + +1. If the first character in the path is a forward-slash, the path is invalid + (absolute paths are not allowed). +2. For every sequence of two or more forward-slashes in the path string, replace + the sequence with a single forward-slash. +3. Remove a final forward-slash in the path string, if present. +4. Split the path string on forward-slashes into a list of *component* strings. +5. Remove every component from the array that is a single ASCII dot "``.``". +6. For each *component* in the path string that is a dot-dot "``..``": + + 1. If the dot-dot component is the first component in the component list, the + path is invalid (The path attempts to reach outside of the CRS package). + 2. Delete the dot-dot component and the component preceeding it in the array. + +7. All remaining path components must also be valid :doc:`CRS names `, except + that they may begin with an ASCII digit. Otherwise the path is invalid. +8. Join the component array with forward-slashes in-between each component. This + is the new path. +9. If the path is an empty string, the path is "``.``". + +After normalizing the library's path, no two libraries may have the same path. +Some platforms may place additional restrictions on library paths. + + +``using`` +========= + +A list of :doc:`names` of other libraries within the same package. Each string must +correspond to the ``name`` property on some other library in the package. A +library cannot "use" itself. The chain of ``using`` should form a acyclic graph. +If a ``using`` string names a non-existent library, or if there is a cycle in +the ``using`` graph, the entire package is invalid. + + +``dependencies`` +================ + +An array of `CRS dependency` objects. + +This array specifies the dependencies of the library within the package. + + +``test-dependencies`` +===================== + +An array of `CRS dependency` objects. + +This array specifies the test-only dependencies of the library within the +package. + + + +Dependencies +############ + +Unlike most packaging formats, dependencies in `CRS` are not associated with +packages at the top-level. Instead, dependencies are associated with individual +libraries within a package. + +.. seealso:: + + - :ref:`Libraries\: External Dependencies ` + - :doc:`The documentation on dependencies and their attributes ` + +A CRS dependency identifies a package by name, one or more version ranges, and +some set of used-libraries. A dependency is associated with a +`library ` within a package, and not with the package as a whole. + +A CRS dependency is specified as a JSON object with the following required +properties: + +.. default-domain:: schematic + +.. mapping:: CRSDependency_v0 + + .. property:: name + :required: + + :type: :ts:`string` + + The name of a package which is being depended-upon. + :doc:`Must be a valid name. ` + + .. property:: using + :required: + + :type: :ts:`string[]` + + An array of |name| strings identifying libraries within the depended-upon + package to be used by the library that contains this dependency. + + .. property:: versions + :required: + + An array of one or more *version range* objects. Each JSON object must contain + the following properties: + + ``low`` + The minimum version of the range. Must be a valid + :hoverxref:`Semantic Version string `. + + ``high`` + The maximum version of the range, exclusive. Must be a valid + :hoverxref:`Semantic Version string `. \ No newline at end of file diff --git a/docs/crs/packages.rst b/docs/crs/packages.rst index eb3479bf..ff8a5157 100644 --- a/docs/crs/packages.rst +++ b/docs/crs/packages.rst @@ -33,25 +33,13 @@ A CRS package encodes the following high-level attributes: package meta-version An integer constant that encodes the revision of the package itself, - regardless of the version of the source code inside. + regardless of the version of the source code inside. Encoded as the + :yaml:`pkg-version` property in |pkg.json|. package libraries - A list of libraries contained within the package. A single package may + A set of libraries contained within the package. A single package may contain any number of libraries. Libraries have further attributes, such as :term:`library internal usages` and :term:`library external dependencies` .. seealso:: :doc:`libraries`. - - -Dependencies -############ - -Unlike most packaging formats, dependencies in `CRS` are not associated with -packages at the top-level. Instead, dependencies are associated with individual -libraries within a package. - -.. seealso:: - - - :ref:`Libraries\: External Dependencies ` - - :doc:`The documentation on dependencies and their attributes ` diff --git a/docs/guide/libraries.rst b/docs/guide/libraries.rst index 093c9c5f..8b27012f 100644 --- a/docs/guide/libraries.rst +++ b/docs/guide/libraries.rst @@ -7,8 +7,9 @@ In |bpt|, all code belongs to a `library`, and every library belongs by either a |bpt| `project` or a `package`. By default, a |bpt| project only has a single `default library`. A project can -be subdivided into more libraries by using the :yaml:`libraries` property. A -library can `depend on ` other libraries in external packages. +be subdivided into more libraries by using the |prop:bpt.yaml:libraries| +property. A library can `depend on ` other libraries in external +packages. |bpt| uses the filesystem layout of the library to derive information about it. Every library has a `library root` directory. A library root contains either @@ -48,7 +49,7 @@ The Default Library ******************* In |bpt|, all code belongs to a `library`. If a |bpt.yaml| file omits the -:yaml:`libraries` property, |bpt| will assume that the `project`'s +|prop:bpt.yaml:libraries| property, |bpt| will assume that the `project`'s `default library` lives in the same directory as |bpt.yaml| and has a library :yaml:`name` equivalent to the project :yaml:`name`: @@ -70,19 +71,20 @@ library is always the same as the `project root`, and cannot be changed. .. seealso:: - The :yaml:`libraries` property allows one to specify any number of libraries - within the project. The :yaml:`libraries` property is discussed below: - :ref:`guide.multiple-libs` + The |prop:bpt.yaml:proj.libraries| property allows one to specify any number + of libraries within the project. The :yaml:`libraries` property is discussed + below: :ref:`guide.multiple-libs` .. note:: If your project only defines a single library, you are likely to not need to - use :yaml:`libraries` and can just rely on the implicit default library. + use |prop:bpt.yaml:proj.libraries| and can just rely on the implicit default + library. .. note:: - If the :yaml:`libraries` property is specified then |bpt| will not generate a - default library. + If the |prop:bpt.yaml:proj.libraries| property is specified then |bpt| will + not generate a default library. .. _guide.multiple-libs: @@ -91,8 +93,8 @@ Multiple Libraries in a Project ******************************* Multiple libraries can be specified for a single `project` by using the -top-level :yaml:`libraries` property in |bpt.yaml|. :yaml:`libraries` must be an -array, and each element must be a map, and each map element must have both a +|prop:bpt.yaml:proj.libraries| property in |bpt.yaml|. :yaml:`libraries` must be +an array, and each element must be a map, and each map element must have both a :yaml:`name` and a :yaml:`path` property: .. code-block:: @@ -330,14 +332,14 @@ Library Properties in |bpt.yaml| ******************************** A |bpt| `project` can declare one or more `libraries ` using the -top-level :ref:`proj.libraries` property in |bpt.yaml|. If the :yaml:`libraries` -property is omitted, |bpt| will instead generate a `default library` for the -project. Most projects will not need to declare explicit :yaml:`libraries` and -can rely on the default library. +top-level |prop:bpt.yaml:proj.libraries| property in |bpt.yaml|. If the +:yaml:`libraries` property is omitted, |bpt| will instead generate a +`default library` for the project. Most projects will not need to declare +explicit :yaml:`libraries` and can rely on the default library. The project's :yaml:`libraries` must be an array, and each element must be a -map, and each map element must at least have both a :yaml:`name` and a -:yaml:`path` property: +:schematic:mapping:`ProjectLibrary` map. The only required properties are +:yaml:`name` and :yaml:`path`: .. code-block:: yaml :caption: |bpt.yaml| @@ -366,71 +368,124 @@ and unquoted identifier keys:: ] } -The :yaml:`name` property must specify a valid `name` for the library, which -must be unique within the project. - -The :yaml:`path` property specifies the `relative filepath` pointing to the -`library root` for the library. This path must be relative to the `project root` -and may only use forward-slash "``/``" as a `directory -separator`. The :yaml:`path` must not "reach outside" of the project root -directory. A path of a single ASCII dot "``.``" refers to the project root -itself. .. note:: - For the `default library` (if :yaml:`libraries` is omitted), the :yaml:`name` - is the same as the project's name, and the :yaml:`path` is "``.``" (equivalent - to the `project root`). + For the `default library` (if |prop:bpt.yaml:proj.libraries| is omitted), the + :yaml:`name` is the same as the project's name, and the :yaml:`path` is + "``.``" (equivalent to the `project root`). + + +.. default-domain:: schematic + +.. rubric:: Schema + +.. mapping:: ProjectLibrary + + A mapping in |bpt.yaml| that defines a `library` for the `project`. These + mapping objects appear as elements of the :prop:`~Project.libraries` array for + the project. + + .. code-block:: yaml + :caption: |bpt.yaml| + :emphasize-lines: 9-11, 13-15 + + name: acme-components + version: 4.1.2 + + # Every library will share the common test-dependencies: + test-dependencies: [catch2@3.0.1] + + # This project defines two libraries listed below: + libraries: + - name: util + path: libs/util + depends: [fmt@8.1.3, asio@1.12.0] + + - name: gui + path: libs/gui + using: [util] # 'gui' uses 'util' + + + .. property:: name + :required: + + :type: string + + The name of the library. Must follow the valid `name` conventions. This name + must be unique within the `project`. + + + .. property:: path + :required: + + :type: string + + The :yaml:`path` property specifies the `relative filepath` pointing to the + `library root` for the library. This path must be relative to the + `project root` (the directory that contains |bpt.yaml|) and may only use + forward-slash "``/``" as a `directory separator`. The :yaml:`path` must not + "reach outside" of the project root directory. A path of a single ASCII dot + "``.``" refers to the project root itself. + + + .. property:: using + :optional: + + :type: string[] + + The internal `dependencies ` of the library. Must be + the names of other libraries within the same `project`. -.. _lib.properties-dl: + .. code-block:: yaml + :emphasize-lines: 10-12 -.. rubric:: Properties + name: acme-items + version: 1.2.3 -.. index:: pair: name; library property -.. _lib.name: + libraries: + - name: widgets + path: libs/widgets -:yaml:`name` : ``string`` - **Required:** The name of the library. Must follow the valid `name` - conventions. This name must be unique within the `project`. + - name: gadgets + path: libs/gadgets + using: [widgets] # All entities from widgets will be + # available to gadgets, as well as to + # any of gadgets' dependents - .. index:: pair: path; library property - .. _lib.path: -:yaml:`path` : ``string`` - **Required:** The `relative filepath` to the `library root`. + .. property:: test-using + :optional: - .. index:: pair: using; library property - .. _lib.using: + :type: string[] -:yaml:`using` : ``string[]`` - *Optional:* The internal `dependencies ` of the library. Must be - the names of other libraries within the same `project`. + The internal `test dependencies ` of the library. Must be + the names of other libraries within the same `project`. Like :prop:`using`, + but these dependencies are only used for building tests. - .. index:: pair: test-using; library property - .. _lib.test-using: -:yaml:`test-using` : ``string[]`` - *Optional:* The internal `test dependencies ` of the - library. Must be the names of other libraries within the same `project`. + .. property:: dependencies + :optional: - .. index:: pair: dependencies; library property - .. _lib.dependencies: + :type: string[] -:yaml:`dependencies` : (See: :doc:`deps`) - *Optional:* The external `dependencies ` of the library. + The external `dependencies ` of the library. If provided, the + value must be an array of `dependency specifier`\ s. - The dependencies here will be merged with the `common dependencies` of the - `project`. + The dependencies here will be merged with the `common dependencies` of the + `project` (from :prop:`Project.dependencies`). - .. seealso:: :doc:`deps` - .. index:: pair: test-dependencies; library property - .. _lib.test-dependencies: + .. property:: test-dependencies + :optional: -:yaml:`test-dependencies` : (See: :doc:`deps`) - *Optional:* The external `test dependencies ` of the library. + :type: string[] - The dependencies here will be merged with the - `common test-dependencies ` of the `project`. + The external `dependencies ` of the library. If provided, the + value must be an array of `dependency specifier`\ s. Like + :prop:`dependencies`, but these dependencies are only used for building + tests. - .. seealso:: :doc:`deps` + The dependencies here will be merged with the + `common test dependencies ` of the `project` (from + :prop:`Project.test-dependencies`. diff --git a/docs/guide/projects.rst b/docs/guide/projects.rst index 656f91a8..75d3a94f 100644 --- a/docs/guide/projects.rst +++ b/docs/guide/projects.rst @@ -70,7 +70,8 @@ When using |bpt|, one is most often working within the scope of a project. A The ``bpt.yaml`` file is placed in the root `directory` of a `project`. It defines the `package` attributes of the project, including the `name`, :ref:`version `, `libraries `, and the - `dependencies ` of those libraries. + `dependencies ` of those libraries. The complete file schema can + be found here: :schematic:mapping:`Project`. .. rubric:: Example @@ -143,90 +144,71 @@ about what makes a valid name and a valid version. All other fields are described below. +.. default-domain:: schematic +.. rubric:: Schema +.. schematic:mapping:: Project -.. index:: - ! pair: name ; project property + This object defines the schema of the |bpt.yaml| file used to define a |bpt| + `project`. -.. _proj.name: + .. property:: name + :required: -:yaml:`name` -************ + :type: string -**This property is requried** + Specifies the `package name` of the `project`. Must fit the + :term:`name rules `. -Specifies the `package name` of the `project`. Must fit the -:term:`name rules `. + .. property:: version + :required: -.. index:: ! pair: version; project property + :type: string -.. _proj.version: + Specifies the `package version` of the `project`. Must be a valid + :ref:`Semantic Version string `. -:yaml:`version` -*************** -**This property is requried** + .. property:: dependencies + :optional: -Specifies the `package version` of the `project`. Must be a valid -:ref:`Semantic Version string `. + :type: string[] + Specify the `common dependencies` of the `project`. If provided, the value + must be an array of `dependency specifier`\ s. -.. index:: ! pair: dependencies; project property + .. seealso:: -.. _proj.dependencies: + - :doc:`deps` + - :prop:`ProjectLibrary.dependencies` -:yaml:`dependencies` -******************** -|prop-optional| + .. property:: test-dependencies + :optional: -Specify the `common dependencies` of the `project`. If provided, the value must -be an array of `dependency specifier`\ s. + :type: string[] -.. seealso:: + Specify the `common test-dependencies ` of the + `project`. If provided, the value must be an array of + `dependency specifier`\ s. - - :doc:`deps` - - :ref:`The library dependencies property ` + .. seealso:: + - :doc:`deps` + - :prop:`ProjectLibrary.test-dependencies` -.. index:: ! pair: test-dependencies; project property -.. _proj.test-dependencies: + .. property:: libraries + :optional: -:yaml:`test-dependencies` -************************* + :type: ProjectLibrary[] -|prop-optional| + Specify the `libraries ` of the `project`. If omitted, |bpt| will + generate a `default library` (recommended for most projects). -Specify the `common test-dependencies ` of the `project`. -If provided, the value must be an array of `dependency specifier`\ s. - -.. seealso:: - - - :doc:`deps` - - :ref:`The library test-dependencies property ` - - -.. index:: ! pair: libraries; project property - -.. _proj.libraries: - -:yaml:`libraries` -***************** - -.. |prop-optional| replace:: *This property is optional* - -|prop-optional| - -Specify the `libraries ` of the `project`. If omitted, |bpt| will -generate a `default library` (recommended for most projects). - -.. seealso:: - - - :ref:`proj.lib-properties` - - :doc:`/guide/libraries` - - :ref:`guide.default-library` - - :ref:`guide.multiple-libs` - -If provided, this must be a non-empty array of library maps. + .. seealso:: + - :ref:`proj.lib-properties` + - :doc:`/guide/libraries` + - :ref:`guide.default-library` + - :ref:`guide.multiple-libs` diff --git a/docs/guide/terms.rst b/docs/guide/terms.rst index ab550d2d..d16ac745 100644 --- a/docs/guide/terms.rst +++ b/docs/guide/terms.rst @@ -155,9 +155,9 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. default library The *default library* of a `project` is the `library` that |bpt| generates - if the :yaml:`libraries` project property is omitted in |bpt.yaml|. It will - have the same :yaml:`name` as the project, and its `library root` will be - the same as the `project root`. + if the :yaml:`libraries` (:schematic:prop:`Project.libraries`) property is + omitted in |bpt.yaml|. It will have the same :yaml:`name` as the project, + and its `library root` will be the same as the `project root`. .. note:: @@ -250,15 +250,15 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. The *common dependencies* of a `project` are the `dependencies ` that appear at the top-level of the project's |bpt.yaml| file. (Refer: - :ref:`proj.dependencies`) + :schematic:prop:`Project.dependencies`) These dependencies are added as direct dependencies of every `library` in the project, whether that is the `default library` or each library in the - :ref:`proj.libraries` array. + :schematic:prop:`Project.libraries` array. The *common test-dependencies* are the similar but apply only to the libraries' `test dependencies `. (Refer: - :ref:`proj.test-dependencies`) + :schematic:prop:`Project.test-dependencies`) package ID diff --git a/docs/guide/toolchains.rst b/docs/guide/toolchains.rst index 2f2be553..c737be13 100644 --- a/docs/guide/toolchains.rst +++ b/docs/guide/toolchains.rst @@ -1,5 +1,6 @@ .. highlight:: js -.. default-role:: tc-option +.. default-domain:: schematic +.. default-role:: schematic:prop .. |--toolchain| replace:: :option:`--toolchain ` @@ -135,9 +136,9 @@ simply one line: compiler_id: "" } -where ```` is one of the known `compiler_id` options. |bpt| will +where ```` is one of the known |compiler_id| options. |bpt| will infer common suitable defaults for the remaining options based on the value of -`compiler_id`. +|compiler_id|. For example, if you specify ``gnu``, then |bpt| will assume ``gcc`` to be the C compiler, ``g++`` to be the C++ compiler, and ``ar`` to be the library archiving @@ -154,11 +155,11 @@ them with additional options: cxx_compiler: 'g++-9', } -|bpt| will continue to infer other options based on the `compiler_id`, but will -use the provided executable names when compiling files for the respective -languages. +|bpt| will continue to infer other options based on the +:prop:`~ToolchainOptions.compiler_id`, but will use the provided executable +names when compiling files for the respective languages. -To specify compilation flags, the `flags ` option can be used: +To specify compilation flags, the `~ToolchainOptions.flags` option can be used: .. code-block:: @@ -169,9 +170,11 @@ To specify compilation flags, the `flags ` option can be used: .. note:: - Use `warning_flags` to specify options regarding compiler warnings. + Use `~ToolchainOptions.warning_flags` to specify options regarding compiler + warnings. -Flags for linking executables can be specified with `link_flags`: +Flags for linking executables can be specified with +`~ToolchainOptions.link_flags`: .. code-block:: @@ -198,7 +201,7 @@ and double ``"`` quote characters as argument delimiters. If an option is given a list of strings instead, then each string in that array is treated as a full command line argument and is passed as such. -For example, this sample with `flags `:: +For example, this sample with `~ToolchainOptions.flags`:: { flags: "-fsanitize=address -fPIC" @@ -214,396 +217,519 @@ Despite splitting strings as-if they were shell commands, |bpt| does nothing else shell-like. It does not expand environment variables, nor does it expand globs and wildcards. +.. mapping:: ToolchainOptions -.. _compiler_id: + .. property:: compiler_id + :optional: -``compiler_id`` ---------------- + :type: :ts:`"gnu" | "clang" | "msvc"` -Specify the identity of the compiler. This option is used to infer many other -facts about the toolchain. If specifying the full toolchain with the command -templates, this option is not required. + Specify the identity of the compiler. This option is used to infer many + other facts about the toolchain. If specifying the full toolchain with the + command templates, this option is not required. -Valid values are: + :option "gnu": For GCC + :option "clang": For LLVM/Clang + :option "msvc": For Microsoft Visual C++ -``gnu`` - For GCC + .. |compiler_id| replace:: :schematic:prop:`~ToolchainOptions.compiler_id` -``clang`` - For LLVM/Clang + .. |gnu| replace:: :ts:`"gnu"` + .. |clang| replace:: :ts:`"clang"` + .. |msvc| replace:: :ts:`"msvc"` -``msvc`` - For Microsoft Visual C++ + .. |default-inferred-from-compiler_id| replace:: + Inferred from the value of |compiler_id| -``c_compiler`` and ``cxx_compiler`` ------------------------------------ -Names/paths of the C and C++ compilers, respectively. Defaults will be inferred -from `compiler_id`. + .. property:: c_compiler + :optional: + .. property:: cxx_compiler + :optional: + :type: string -.. _c_version: -.. _cxx_version: + Names/paths of the C and C++ compilers, respectively. -``c_version`` and ``cxx_version`` ---------------------------------- + :default: |default-inferred-from-compiler_id|: -Specify the language versions for C and C++, respectively. By default, |bpt| -will not set any language version. Using this option requires that the -`compiler_id` be specified (Or the `lang_version_flag_template` advanced -setting). + - When |compiler_id| is |gnu|: -Examples of `c_version ` values are: + - :prop:`c_compiler`: ``gcc`` + - :prop:`cxx_compiler`: ``g++`` -- ``c89`` -- ``c99`` -- ``c11`` -- ``c18`` + - When |compiler_id| is |clang|: -Examples of `cxx_version ` values are: + - :prop:`c_compiler`: ``clang`` + - :prop:`cxx_compiler`: ``clang++`` -- ``c++14`` -- ``c++17`` -- ``c++20`` + - When |compiler_id| is |msvc|: ``cl.exe`` (for both C and C++) -The given string will be substituted in the appropriate compile flag to specify -the language version being passed. + .. property:: c_version + :optional: + .. property:: cxx_version + :optional: -To enable GNU language extensions on GNU compilers, one can values like -``gnu++20``, which will result in ``-std=gnu++20`` being passed. Likewise, if -the language version is "experimental" in your GCC release, you may set -`cxx_version ` to the appropriate experimental version name, e.g. -``"c++2a"`` for ``-std=c++2a``. + Specify the language versions for C and C++, respectively. By default, |bpt| + will not set any language version. Using this option requires that the + :prop:`~ToolchainOptions.compiler_id` be specified (Or the + :prop:`~AdvancedToolchainOptions.lang_version_flag_template` advanced + setting). -For MSVC, setting `cxx_version ` to ``c++latest`` will result in -``/std:c++latest``. **Beware** that this is an unstable setting value that could -change the major language version in a future MSVC update. + Examples of :yaml:`c_version` values are: + - ``c89`` + - ``c99`` + - ``c11`` + - ``c18`` -.. _warning_flags: + Examples of :yaml:`cxx_version` values are: -``warning_flags`` ------------------ + - ``c++14`` + - ``c++17`` + - ``c++20`` -Provide *additional* compiler flags that should be used to enable warnings. This -option is stored separately from `flags `, as these options may be -enabled/disabled separately depending on how |bpt| is invoked. + The given string will be substituted in the appropriate compile flag to + specify the language version being passed. -.. note:: + To enable GNU language extensions on GNU compilers, one can values like + ``gnu++20``, which will result in ``-std=gnu++20`` being passed. Likewise, + if the language version is "experimental" in your GCC release, you may set + :yaml:`cxx_version` to the appropriate experimental version name, e.g. + ``"c++2a"`` for ``-std=c++2a``. - If `compiler_id` is provided, a default set of warning flags will be - provided when warnings are enabled. + For MSVC, setting :yaml:`cxx_version` to ``c++latest`` will result in + ``/std:c++latest``. **Beware** that this is an unstable setting value that + could change the major language version in a future MSVC update. - Adding flags to this toolchain option will *append* flags to the basis - warning flag list rather than overwrite them. + .. property:: warning_flags + :optional: -.. seealso:: + :type: :ts:`string | string[]` + :default: :ts:`[]` - Refer to :ref:`toolchains.opts.base_warning_flags` for more information. + Provide *additional* compiler flags that should be used to enable warnings. + This option is stored separately from :prop:`flags`, as these options may be + enabled/disabled separately depending on how |bpt| is invoked. + .. note:: -.. _flags: + If :prop:`~ToolchainOptions.compiler_id` is provided, a default set of + warning flags will be provided when warnings are enabled. -``flags``, ``c_flags``, and ``cxx_flags`` ------------------------------------------ + Adding flags to this toolchain option will *append* flags to the basis + warning flag list rather than overwrite them. -Specify *additional* compiler options, possibly per-language. + .. seealso:: + Refer to :prop:`AdvancedToolchainOptions.base_warning_flags` for more + information. -.. _link_flags: -``link_flags`` --------------- + .. property:: flags + :optional: + .. property:: c_flags + :optional: + .. property:: cxx_flags + :optional: -Specify *additional* link options to use when linking executables. + :type: :ts:`string | string[]` + :default: :ts:`[]` -.. note:: + Specify *additional* compiler options, possibly per-language. :yaml:`flags` + will apply to all languages. - |bpt| does not invoke the linker directly, but instead invokes the - compiler with the appropriate flags to perform linking. If you need to pass - flags directly to the linker, you will need to use the compiler's options to - direct flags through to the linker. On GNU-style, this is - ``-Wl,``. With MSVC, a separate flag ``/LINK`` must be - specified, and all following options are passed to the underlying - ``link.exe``. + .. property:: link_flags + :optional: + :type: :ts:`string | string[]` + :default: :ts:`[]` -``optimize`` ------------- + Specify *additional* link options to use when linking executables. -Boolean option (|true| or |false|) to enable/disable optimizations. Default -is |false|. + .. note:: + |bpt| does not invoke the linker directly, but instead invokes the + compiler with the appropriate flags to perform linking. If you need to + pass flags directly to the linker, you will need to use the compiler's + options to direct flags through to the linker. On GNU-style, this is + ``-Wl,``. With MSVC, a separate flag ``/LINK`` must be + specified, and all following options are passed to the underlying + ``link.exe``. -``debug`` ---------- -Bool or string. Default is |false|. If |true| or ``"embedded"``, generates -debug information embedded in the compiled binaries. If ``"split"``, generates -debug information in a separate file from the binaries. + .. property:: optimize + :optional: -.. note:: - ``"split"`` with GCC requires that the compiler support the - ``-gsplit-dwarf`` option. + :type: :ts:`boolean` + :default: |false| + Enable/disable compiler optimizations. -``runtime`` ------------ -Select the language runtime/standard library options. Must be an object, and supports two keys: + .. property:: debug + :optional: -``static`` - A boolean. If |true|, the runtime and standard libraries will be - static-linked into the generated binaries. If |false|, they will be - dynamically linked. Default is |true| with MSVC, and |false| with GCC - and Clang. + :type: :ts:`boolean | "embedded" | "split"` + :default: |false| -``debug`` - A boolean. If |true|, the debug versions of the runtime and standard - library will be compiled and linked into the generated binaries. If - |false|, the default libraries will be used. + :option "embedded": - **On MSVC** the default value depends on the top-level ``/debug`` option: If - ``/debug`` is not |false|, then ``/runtime/debug`` defaults to |true|. + Generates debug information embedded in the compiled binaries. - **On GCC and Clang** the default value is |false|. + :option split: -.. note:: + Generates debug information in a separate file from the compiled binaries. - On GNU-like compilers, ``static`` does not generate a static executable, it - only statically links the runtime and standard library. To generate a static - executable, the ``-static`` option should be added to ``link_flags``. + .. note:: -.. note:: + ``"split"`` with GCC requires that the compiler support the + ``-gsplit-dwarf`` option. + + :option true: Same as :ts:`"embedded"` + + :option false: Do not generate any debug information. + + + .. property:: runtime + :optional: + + :type: :ts:`{static?: boolean, debug?: boolean}` + + Select the language runtime/standard library options. Must be an object, and + supports two sub-properties: + + .. property:: static + :optional: + + :type: boolean + + A boolean. If |true|, the runtime and standard libraries will be + static-linked into the generated binaries. If |false|, they will be + dynamically linked. Default is |true| with MSVC, and |false| with GCC and + Clang. - On GNU and Clang, setting ``/runtime/debug`` to |true| will compile all - files with the ``_GLIBCXX_DEBUG`` and ``_LIBCPP_DEBUG=1`` preprocessor - definitions set. **Translation units compiled with these macros are - definitively ABI-incompatible with TUs that have been compiled without these - options!!** + .. property:: debug + :optional: - If you link to a static or dynamic library that has not been compiled with - the same runtime settings, generated programs will likely crash. + :type: boolean + :default: + - If |compiler_id| is |msvc|, the default value depends on the top-level + :prop:`ToolchainOptions.debug` option: If :yaml:`debug` is not + |false|, then :yaml:`runtime.debug` defaults to |true|. + - Otherwise, the default value is |false|. -``compiler_launcher`` ---------------------- + A boolean. If |true|, the debug versions of the runtime and standard + library will be compiled and linked into the generated binaries. If + |false|, the default libraries will be used. -Provide a command prefix that should be used on all compiler executions. -e.g. ``ccache``. + .. note:: + On GNU-like compilers, setting :prop:`ToolchainOptions.runtime.static` to + |true| does not generate a static executable: it only statically links the + runtime and standard library. To generate a static executable, the + ``-static`` option should be added to ``link_flags``. -``advanced`` ------------- + .. note:: -A nested object that contains advanced toolchain options. Refer to section on -advanced toolchain options. + On GNU and Clang, setting :yaml:`runtime.debug` to |true| will compile all + files with the ``_GLIBCXX_DEBUG`` and ``_LIBCPP_DEBUG=1`` preprocessor + definitions set. **Translation units compiled with these macros are + definitively ABI-incompatible with TUs that have been compiled without + these options!!** + + If you link to a static or dynamic library that has not been compiled with + the same runtime settings, generated programs will likely crash. + + + .. property:: compiler_launcher + :optional: + + :type: :ts:`string | string[]` + + Provide a command prefix that should be used on all compiler executions. + e.g. ``ccache``. + + .. property:: advanced + :optional: + + :type: AdvancedToolchainOptions + + A nested object that contains advanced toolchain options. These settings + should be handled with care. Advanced Options Reference ************************** -The options below are probably not good to tweak unless you *really* know what -you are doing. Their values will be inferred from `compiler_id`. +.. mapping:: AdvancedToolchainOptions + The options below are probably not good to tweak unless you *really* know what + you are doing. Their values will be inferred from + :prop:`~ToolchainOptions.compiler_id`. -Command Templates ------------------ + .. _command template: -Many of the below options take the form of command-line templates. These are -templates from which |bpt| will create a command-line for a subprocess, -possibly by combining them together. + .. rubric:: Command Templates -Each command template allows some set of placeholders. Each instance of the -placeholder string will be replaced in the final command line. Refer to each -respective option for more information. + Many of the below options take the form of command-line templates. These are + templates from which |bpt| will create a command-line for a subprocess, + possibly by combining them together. + Each command template allows some set of placeholders. Each instance of the + placeholder string will be replaced in the final command line. Refer to each + respective option for more information. -``deps_mode`` -------------- + .. property:: deps_mode + :optional: -Specify the way in which |bpt| should track compilation dependencies. One -of ``gnu``, ``msvc``, or ``none``. + :type: :ts:`"gnu" | "msvc" | "none"` -.. note:: - If ``none``, then dependency tracking will be disabled entirely. This will - prevent |bpt| from tracking interdependencies of source files, and - inhibits incremental compilation. + Specify the way in which |bpt| should track compilation dependencies. One of + ``gnu``, ``msvc``, or ``none``. + :default: |default-inferred-from-compiler_id|. -``c_compile_file`` and ``cxx_compile_file`` -------------------------------------------- + .. note:: -Override the *command template* that is used to compile source files. + If ``none``, then dependency tracking will be disabled entirely. This will + prevent |bpt| from tracking interdependencies of source files, and + inhibits incremental compilation. -This template expects three placeholders: + .. property:: c_compile_file + :optional: + .. property:: cxx_compile_file + :optional: -- ``[in]`` is the path to the file that will be compiled. -- ``[out]`` is the path to the object file that will be generated. -- ``[flags]`` is the placeholder of the compilation flags. This placeholder - must not be attached to any other arguments. The compilation flag argument - list will be inserted in place of ``[flags]``. + :type: :ts:`string | string[]` -Defaults:: + Override the `command template`_ that is used to compile source files. - { - // On GNU-like compilers (GCC, Clang): - c_compile_file: " [flags] -c [in] -o[out]", - cxx_compile_file: " [flags] -c [in] -o[out]", + :placeholder [in]: The path to the source file that will be compiled. + :placeholder [out]: The path to the object file that will be generated. - // On MSVC: - c_compile_file: "cl.exe [flags] /c [in] /Fo[out]", - cxx_compile_file: "cl.exe [flags] /c [in] /Fo[out]", - } + :placeholder [flags]: + The placeholder of the compilation flags. This placeholder must not be + attached to any other arguments. The compilation flag argument list will + be inserted in place of ``[flags]``. -``create_archive`` ------------------- + :default: |default-inferred-from-compiler_id|: -Override the *command template* that is used to generate static library archive -files. + - If |compiler_id| is |msvc|, then: -This template expects two placeholders: + - :prop:`c_compile_file` is :ts:` [flags] /c [in] /Fo[out]` + - :prop:`cxx_compile_file` is :ts:` [flags] /c [in] /Fo[out]` -- ``[in]`` is the a placeholder for the list of inputs. It must not be attached - to any other arguments. The list of input paths will be inserted in place of - ``[in]``. -- ``[out]`` is the placeholder for the output path for the static library - archive. + - If |compiler_id| is |gnu| or |clang|, then: -Defaults:: + - :prop:`c_compile_file` is :ts:` [flags] -c [in] -o[out]` + - :prop:`cxx_compile_file` is :ts:` [flags] -c [in] -o[out]` - { - // On GNU-like: - create_archive: "ar rcs [out] [in]", - // On MSVC: - create_archive: "lib /nologo /OUT:[out] [in]", - } + - If |compiler_id| is unset, then this property must be specified. -``link_executable`` -------------------- + .. property:: create_archive + :optional: -Override the *command template* that is used to link executables. + :type: :ts:`string | string[]` -This template expects the same placeholders as ``create_archive``, but -``[out]`` is a placeholder for the executable file rather than a static -library. + Override the `command template`_ that is used to generate static library + archive files. -Defaults:: + :placeholder [in]: - { - // For GNU-like: - link_executable: " -fPIC [in] -pthread -o[out] [flags]", - // For MSVC: - link_executable: "cl.exe /nologo /EHsc [in] /Fe[out]", - } + The list of inputs. It must not be attached to any other arguments. The + list of input paths will be inserted in place of ``[in]``. + + :placeholder [out]: + + The placeholder for the output path for the static library archive. + + :default: |default-inferred-from-compiler_id|: + + - If |compiler_id| is |msvc|, then ``lib /nologo /OUT:[out] [in]`` + - If |compiler_id| is |gnu| or |clang|, then ``ar rcs [out] [in]`` + - If |compiler_id| is unset, then this property must be specified. + + + .. property:: link_executable + :optional: + + :type: :ts:`string | string[]` + + Override the `command template`_ that is used to link executables. + + :placeholder [in]: + + The list of input filepaths. It must not be attached to any other + arguments. The list of input paths will be inserted in place of ``[in]``. + + :placeholder [out]: + + The placeholder for the output path for the executable file. + + :default: |default-inferred-from-compiler_id|: + + - If |compiler_id| is |msvc|, then + `` /nologo /EHsc [in] /Fe[out]`` + - If |compiler_id| is |gnu| or |clang|, then + `` -fPIC [in] -pthread -o[out] [flags]`` + - If |compiler_id| is unset, then this property must be specified. + + + .. property:: include_template + :optional: + .. property:: external_include_template + :optional: + + :type: :ts:`string | string[]` + + Override the `command template`_ for the flags to specify a header search + path. ``external_include_template`` will be used to specify the include + search path for a directory that is "external" (i.e. does not live within + the main project). + + For each directory added to the ``#include`` search path, this argument + template is instantiated in the ``[flags]`` for the compilation. + + :placeholder [path]: + + The path to the directory to be added to the search path. + + :default: |default-inferred-from-compiler_id|: + + - If |compiler_id| is |msvc|, then ``/I [path]``. + - If |compiler_id| is |gnu| or |clang|: + - :prop:`include_template` is ``-I [path]``. + - :prop:`extern_include_template` is ``-isystem [path]``. + - If |compiler_id| is unset, then this property must be specified. + + + .. property:: define_template + :optional: + + :type: :ts:`string | string[]` + Override the `command template`_ for the flags to set a preprocessor + definition. -``include_template`` and ``external_include_template`` ------------------------------------------------------- + :placeholder [def]: -Override the *command template* for the flags to specify a header search path. -``external_include_template`` will be used to specify the include search path -for a directory that is "external" (i.e. does not live within the main project). + The preprocessor macro definition to define. -For each directory added to the ``#include`` search path, this argument -template is instantiated in the ``[flags]`` for the compilation. + :default: |default-inferred-from-compiler_id|: -This template expects only a single placeholder: ``[path]``, which will be -replaced with the path to the directory to be added to the search path. + - If |compiler_id| is |msvc|, then ``/D [path]``. + - If |compiler_id| is |gnu| or |clang|, then ``-D [path]``. + - If |compiler_id| is unset, then this property must be specified. -On MSVC, this defaults to ``/I [path]``. On GNU-like, ``-isystem [path]`` is -used for ``external_include_template`` and ``-I [path]`` for -``include_template``. + .. property:: lang_version_flag_template + :optional: -``define_template`` -------------------- + :type: :ts:`string|string[]` -Override the *command template* for the flags to set a preprocessor definition. + Set the flag template string for the language-version specifier for the + compiler command line. -This template expects only a single placeholder: ``[def]``, which is the -preprocessor macro definition argument. + :placeholder [version]: -On MSVC, this defaults to ``/D [def]``. On GNU-like compilers, this is -``-D [def]``. + The version string passed for :prop:`c_version` or :prop:`cxx_version`. + This template expects a single placeholder: ``[version]``, which is -.. _lang_version_flag_template: + On MSVC, this defaults to ``/std:[version]``. On GNU-like compilers, it + defaults to ``-std=[version]``. -``lang_version_flag_template`` ------------------------------- -Set the flag template string for the language-version specifier for the -compiler command line. + .. property:: tty_flags + :optional: -This template expects a single placeholder: ``[version]``, which is the version -string passed for `c_version` or `cxx_version`. + :type: :ts:`string|string[]` -On MSVC, this defaults to ``/std:[version]``. On GNU-like compilers, it -defaults to ``-std=[version]``. + Supply additional flags when compiling/linking that will only be applied if + standard output is an ANSI-capable terminal. + On GNU and Clang this will be ``-fdiagnostics-color`` by default. -``tty_flags`` -------------- -Supply additional flags when compiling/linking that will only be applied if -standard output is an ANSI-capable terminal. + .. property:: obj_prefix + :optional: + .. property:: obj_suffix + :optional: + .. property:: archive_prefix + :optional: + .. property:: archive_suffix + :optional: + .. property:: exe_prefix + :optional: + .. property:: exe_suffix + :optional: -On GNU and Clang this will be ``-fdiagnostics-color`` by default. + :type: :ts:`string` + Set the filename prefixes and suffixes for object files, library archive + files, and executable files, respectively. -``obj_prefix``, ``obj_suffix``, ``archive_prefix``, ``archive_suffix``, ``exe_prefix``, and ``exe_suffix`` ----------------------------------------------------------------------------------------------------------- + :default: -Set the filename prefixes and suffixes for object files, library archive files, -and executable files, respectively. + |default-inferred-from-compiler_id| and the host system on which |bpt| is + executing. -.. _toolchains.opts.base_warning_flags: + .. property:: base_warning_flags + :optional: -``base_warning_flags`` ----------------------- + :type: :ts:`string | string[]` -When you compile your project and request warning flags, |bpt| will -concatenate the warning flags from this option with the flags provided by -`warning_flags`. This option is "advanced," because it provides a set of -defaults based on the `compiler_id`. + When you compile your project and request warning flags, |bpt| will + concatenate the warning flags from this option with the flags provided by + `warning_flags`. This option is "advanced," because it provides a set of + defaults based on the :prop:`~ToolchainOptions.compiler_id`. -On GNU-like compilers, the base warning flags are ``-Wall -Wextra -Wpedantic --Wconversion``. On MSVC the default flag is ``/W4``. + On GNU-like compilers, the base warning flags are + ``-Wall -Wextra -Wpedantic -Wconversion``. On MSVC the default flag is + ``/W4``. -For example, if you set `warning_flags` to ``"-Werror"`` on a GNU-like -compiler, the resulting command line will contain ``-Wall -Wextra -Wpedantic --Wconversion -Werror``. + For example, if you set `warning_flags` to ``"-Werror"`` on a GNU-like + compiler, the resulting command line will contain + ``-Wall -Wextra -Wpedantic -Wconversion -Werror``. -.. _toolchains.opts.base_flags: + .. property:: base_flags + :optional: + .. property:: base_c_flags + :optional: + .. property:: base_cxx_flags + :optional: -``base_flags``, ``base_c_flags``, and ``base_cxx_flags`` --------------------------------------------------------- + :type: :ts:`string | string[]` -When you compile your project, |bpt| uses a set of default flags appropriate to -the target language and compiler. These flags are always included in the compile -command and are inserted in addition to those flags provided by `flags`. + When you compile your project, |bpt| uses a set of default flags appropriate + to the target language and compiler. These flags are always included in the + compile command and are inserted in addition to those flags provided by + `flags`. -On GNU-like compilers, the base flags are ``-fPIC -pthread``. On -MSVC the default flags are ``/EHsc /nologo /permissive-`` for C++ and ``/nologo -/permissive-`` for C. + On GNU-like compilers, the base flags are ``-fPIC -pthread``. On MSVC the + default flags are ``/EHsc /nologo /permissive-`` for C++ and + ``/nologo /permissive-`` for C. -These defaults may be changed by providing values for three different options. -The ``base_flags`` value is always output, regardless of language. Flags -exclusive to C are specified in ``base_c_flags``, and those exclusively for -C++ should be in ``base_cxx_flags``. Note that the language-specific values are -independent from ``base_flags``; that is, providing ``base_c_flags`` or -``base_cxx_flags`` does not override or prevent the inclusion of the -``base_flags`` value, and vice-versa. Empty values are acceptable, should you -need to simply prohibit one or more of the defaults from being used. + These defaults may be changed by providing values for three different + options. The ``base_flags`` value is always output, regardless of language. + Flags exclusive to C are specified in ``base_c_flags``, and those + exclusively for C++ should be in ``base_cxx_flags``. Note that the + language-specific values are independent from ``base_flags``; that is, + providing ``base_c_flags`` or ``base_cxx_flags`` does not override or + prevent the inclusion of the ``base_flags`` value, and vice-versa. Empty + values are acceptable, should you need to simply prohibit one or more of the + defaults from being used. -For example, if you set `flags ` to ``-ansi`` on a GNU-like compiler, the -resulting command line will contain ``-fPIC -pthread -ansi``. If, additionally, -you set ``base_flags`` to ``-fno-builtin`` and ``base_cxx_flags`` to -``-fno-exceptions``, the generated command will include -``-fno-builtin -fno-exceptions -ansi`` for C++ and ``-fno-builtin -ansi`` for C. + For example, if you set `ToolchainOptions.flags` to ``-ansi`` on a GNU-like + compiler, the resulting command line will contain ``-fPIC -pthread -ansi``. + If, additionally, you set ``base_flags`` to ``-fno-builtin`` and + ``base_cxx_flags`` to ``-fno-exceptions``, the generated command will + include ``-fno-builtin -fno-exceptions -ansi`` for C++ and + ``-fno-builtin -ansi`` for C. diff --git a/docs/prolog.rst b/docs/prolog.rst index 0225541d..f503fe8b 100644 --- a/docs/prolog.rst +++ b/docs/prolog.rst @@ -24,10 +24,15 @@ :language: cpp :class: highlight +.. role:: ts(code) + :language: typescript + :class: highlight + .. |#include| replace:: :cpp:`#include` .. |true| replace:: :cpp:`true` .. |false| replace:: :cpp:`false` -.. role:: tc-option(ref) +.. |prop:bpt.yaml:proj.libraries| replace:: :schematic:prop:`Project.libraries` +.. |prop:bpt.yaml:libraries| replace:: :schematic:prop:`libraries ` From 167055a5479c7fb8a13e141e2480ec22a05aea30 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 16 Jun 2022 21:44:51 -0600 Subject: [PATCH 45/62] Accept "gcc" for compiler_id --- src/bpt/toolchain/from_json.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bpt/toolchain/from_json.cpp b/src/bpt/toolchain/from_json.cpp index e17f4827..6e26a76f 100644 --- a/src/bpt/toolchain/from_json.cpp +++ b/src/bpt/toolchain/from_json.cpp @@ -224,7 +224,7 @@ toolchain bpt::parse_toolchain_json_data(const json5::data& dat, std::string_vie }, }, }, - [&](auto key, auto &&) -> walk_result { + [&](auto key, auto&&) -> walk_result { // They've given an unknown key. Ouch. auto dym = did_you_mean(key, { @@ -262,7 +262,7 @@ toolchain bpt::parse_toolchain_json_data(const json5::data& dat, std::string_vie return no_comp_id; } else if (compiler_id == "msvc") { return msvc; - } else if (compiler_id == "gnu") { + } else if (compiler_id == "gnu" or compiler_id == "gcc") { return gnu; } else if (compiler_id == "clang") { return clang; From 703757890b548afec3e1e164e6cddd4e366f3d35 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 16 Jun 2022 22:17:37 -0600 Subject: [PATCH 46/62] Support --if-missing for 'repo remove' [Implements #130] --- src/bpt/cli/cmd/repo_remove.cpp | 15 ++++++++++++++- src/bpt/cli/options.cpp | 4 +++- src/bpt/crs/repo.cpp | 22 +++++++++++++++++----- tests/test_repo/test_repo.py | 19 +++++++++++++++++++ tools/bpt_ci/testing/repo.py | 10 ++++++++++ 5 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/bpt/cli/cmd/repo_remove.cpp b/src/bpt/cli/cmd/repo_remove.cpp index 98da21f1..dfe2459b 100644 --- a/src/bpt/cli/cmd/repo_remove.cpp +++ b/src/bpt/cli/cmd/repo_remove.cpp @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include // for e_nonesuch_package #include #include @@ -23,7 +25,18 @@ int repo_remove(const options& opts) { /// We only need the name and version info to do the removal bpt::crs::package_info meta; meta.id = pkg_id; - repo.remove_pkg(meta); + bpt_leaf_try { repo.remove_pkg(meta); } + bpt_leaf_catch(bpt::e_nonesuch_package missing) { + if (opts.if_missing == if_missing::ignore) { + bpt_log(info, + "Ignoring non-existent package .bold.yellow[{}]"_styled, + missing.given); + } else { + missing.log_error("No such package .bold.red[{}]"_styled); + write_error_marker("pkg-remove-nonesuch"); + bpt::throw_system_exit(1); + } + }; } return 0; } diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 5bb31cca..e8aed8b3 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -380,7 +380,7 @@ struct setup { void setup_repo_init_cmd(argument_parser& repn_init_cmd) { repn_init_cmd.add_argument(repo_repo_dir_arg.dup()); repn_init_cmd.add_argument(if_exists_arg.dup()).help - = "What to do if the directory exists and is already repository"; + = "What to do if the directory exists and is already a repository"; repn_init_cmd.add_argument({ .long_spellings = {"name"}, .short_spellings = {"n"}, @@ -393,6 +393,8 @@ struct setup { void setup_repo_remove_cmd(argument_parser& repo_remove_cmd) { repo_remove_cmd.add_argument(repo_repo_dir_arg.dup()); + repo_remove_cmd.add_argument(if_missing_arg.dup()).help + = "What to do if the request package does not exist in the repository"; repo_remove_cmd.add_argument({ .help = "One or more identifiers of packages to remove", .valname = "", diff --git a/src/bpt/crs/repo.cpp b/src/bpt/crs/repo.cpp index bfa312fe..0e83f297 100644 --- a/src/bpt/crs/repo.cpp +++ b/src/bpt/crs/repo.cpp @@ -2,11 +2,13 @@ #include "./error.hpp" +#include #include #include #include #include #include +#include // for e_nonesuch_package #include #include #include @@ -17,8 +19,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -213,16 +217,24 @@ neo::any_input_range repository::all_latest_rev_packages() const { void repository::remove_pkg(const package_info& meta) { auto to_delete = subdir_of(meta); - db_exec(_prepare(R"( + auto rows = neo::sqlite3::exec_rows(_prepare(R"( DELETE FROM crs_repo_packages WHERE name = ?1 AND version = ?2 AND (pkg_version = ?3) + RETURNING 1 )"_sql), - meta.id.name.str, - meta.id.version.to_string(), - meta.id.revision) - .value(); + meta.id.name.str, + meta.id.version.to_string(), + meta.id.revision) + .value(); + auto n_deleted = std::ranges::distance(rows); + if (n_deleted == 0) { + auto req_id = meta.id.to_string(); + auto all_ids = this->all_packages() | neo::lref + | std::views::transform([](auto inf) { return inf.id.to_string(); }) | neo::to_vector; + BOOST_LEAF_THROW_EXCEPTION(bpt::e_nonesuch_package{req_id, did_you_mean(req_id, all_ids)}); + } bpt_log(debug, "Deleting subdirectory [{}]", to_delete.string()); ensure_absent(to_delete).value(); } diff --git a/tests/test_repo/test_repo.py b/tests/test_repo/test_repo.py index 490a5507..b2219b45 100644 --- a/tests/test_repo/test_repo.py +++ b/tests/test_repo/test_repo.py @@ -177,6 +177,25 @@ def test_repo_double_import_replace(bpt: BPTWrapper, simple_repo: CRSRepo) -> No assert before_time < after_time +def test_repo_remove(simple_repo: CRSRepo) -> None: + assert simple_repo.path.joinpath('pkg/test-pkg/1.2.43~1').exists() + simple_repo.remove('test-pkg@1.2.43~1') + assert not simple_repo.path.joinpath('pkg/test-pkg/1.2.43~1').exists() + + +def test_repo_remove_twice(simple_repo: CRSRepo) -> None: + simple_repo.remove('test-pkg@1.2.43~1') + with expect_error_marker('pkg-remove-nonesuch'): + simple_repo.remove('test-pkg@1.2.43~1') + + +def test_repo_remove_ignore_missing(simple_repo: CRSRepo) -> None: + simple_repo.remove('test-pkg@1.2.43~1') + simple_repo.remove('test-pkg@1.2.43~1', if_missing='ignore') + with expect_error_marker('pkg-remove-nonesuch'): + simple_repo.remove('test-pkg@1.2.43~1', if_missing='fail') + + def test_pkg_prefetch_http_url(bpt: BPTWrapper, simple_repo: CRSRepo, http_server_factory: HTTPServerFactory, tmp_path: Path) -> None: srv = http_server_factory(simple_repo.path) diff --git a/tools/bpt_ci/testing/repo.py b/tools/bpt_ci/testing/repo.py index 12a75757..0d4f7884 100644 --- a/tools/bpt_ci/testing/repo.py +++ b/tools/bpt_ci/testing/repo.py @@ -41,6 +41,16 @@ def import_(self, if validate: self.validate() + def remove(self, name: str, if_missing: Literal[None, 'ignore', 'fail'] = None) -> None: + self.bpt.run([ + '-ldebug', + 'repo', + 'remove', + self.path, + name, + (() if if_missing is None else f'--if-missing={if_missing}'), + ]) + def validate(self) -> None: self.bpt.run(['repo', 'validate', self.path, '-ldebug']) From dcec1c7cb8628ddf4f95a6e548e968a13fde98dc Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Thu, 16 Jun 2022 22:25:42 -0600 Subject: [PATCH 47/62] Fix repo sharing in test_repo --- tests/test_repo/test_repo.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/test_repo/test_repo.py b/tests/test_repo/test_repo.py index b2219b45..11af2d36 100644 --- a/tests/test_repo/test_repo.py +++ b/tests/test_repo/test_repo.py @@ -10,7 +10,7 @@ from bpt_ci.testing.http import HTTPServerFactory from bpt_ci.testing import Project from bpt_ci.testing.error import expect_error_marker -from bpt_ci.testing.repo import CRSRepo, CRSRepoFactory, make_simple_crs +from bpt_ci.testing.repo import CRSRepo, CRSRepoFactory, RepoCloner, make_simple_crs def test_repo_init(tmp_crs_repo: CRSRepo) -> None: @@ -150,7 +150,7 @@ def test_repo_import_db_invalid3(bpt: BPTWrapper, tmp_path: Path, tmp_project: P @pytest.fixture(scope='session') -def simple_repo(crs_repo_factory: CRSRepoFactory) -> CRSRepo: +def simple_repo_base(crs_repo_factory: CRSRepoFactory) -> CRSRepo: repo = crs_repo_factory('simple') names = ('simple.crs', 'simple2.crs', 'simple3.crs', 'simple4.crs') simples = (PROJECT_ROOT / 'data' / name for name in names) @@ -158,6 +158,11 @@ def simple_repo(crs_repo_factory: CRSRepoFactory) -> CRSRepo: return repo +@pytest.fixture() +def simple_repo(simple_repo_base: CRSRepo, clone_repo: RepoCloner) -> CRSRepo: + return clone_repo(simple_repo_base) + + def test_repo_double_import(bpt: BPTWrapper, simple_repo: CRSRepo) -> None: with expect_error_marker('repo-import-pkg-already-exists'): simple_repo.import_(PROJECT_ROOT / 'data/simple.crs') From 19538478b69972c091a926ec41cfa0f955127584 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 18 Jun 2022 21:33:59 -0600 Subject: [PATCH 48/62] MSVC has trouble with many lambdas that refer to themself --- src/bpt/build/builder.cpp | 77 +++++++++++++-------------------------- 1 file changed, 26 insertions(+), 51 deletions(-) diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index 4f1b2058..57728ed0 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -66,12 +67,34 @@ library_plan prepare_library(const sdist_target& sdt, return library_plan::create(sdt.sd.path, pkg_man, lib, std::move(lp)); } +static void activate_more(neo::output> libs_to_build, + std::map const& all_libs, + const lib_prep_info& inf) { + auto did_insert = libs_to_build.get().emplace(&inf).second; + if (not did_insert) { + return; + } + for (crs::dependency const& dep : inf.lib.dependencies) { + for (bpt::name const& used_name : dep.uses) { + auto found = all_libs.find(lm::usage{dep.name.str, used_name.str}); + neo_assert(invariant, + found != all_libs.end(), + "Failed to find a dependency library for build activation", + inf.lib.name, + dep.name, + used_name); + activate_more(libs_to_build, all_libs, found->second); + } + } +} + build_plan prepare_build_plan(neo::ranges::range_of auto&& sdists) { build_plan plan; // First generate a mapping of all libraries std::map all_libs; // Keep track of which libraries we want to build: std::set libs_to_build; + std::set leaf_libs_to_build; // Iterate all loaded sdists: for (const sdist_target& sdt : sdists) { for (const auto& lib : sdt.sd.pkg.libraries) { @@ -86,60 +109,12 @@ build_plan prepare_build_plan(neo::ranges::range_of auto&& sdists) .first->second; // If the sdist_build_params wants libraries, activate them now: if (ranges::contains(sdt.params.build_libraries, lib.name)) { - libs_to_build.emplace(&lpi); + leaf_libs_to_build.emplace(&lpi); } } } - // Recursive library activator: - std::function activate_more = [&](const lib_prep_info& inf) { - auto add_deps = [&](auto&& deps) { - for (const auto& dep : deps) { - for (const auto& use : dep.uses) { - std::function add_named - = [&](bpt::name const& libname) { - // All libraries that we are using must have been loaded into the - // builder (i.e. by the package dependency solver) - auto found = all_libs.find(lm::usage{dep.name.str, libname.str}); - neo_assert(invariant, - found != all_libs.end(), - "Failed to find a dependency library for build activation", - inf.lib.name, - dep.name, - libname); - bool did_add = libs_to_build.emplace(&found->second).second; - if (did_add) { - bpt_log(trace, - "Activate library [{}/{}] (Required by {}/{})", - dep.name, - libname, - inf.pkg.id.name, - inf.lib.name); - // Recursively activate more libraries used by this library. - activate_more(found->second); - } - for (const auto& sibling : found->second.lib.intra_using) { - add_named(sibling); - } - if (inf.sdt.params.build_tests) { - for (const auto& sibling : found->second.lib.intra_test_using) { - add_named(sibling); - } - } - }; - add_named(use); - } - } - }; - add_deps(inf.lib.dependencies); - if (!inf.sdt.params.build_tests) { - return; - } - // We also need to build test dependencies - add_deps(inf.lib.test_dependencies); - }; - // Now actually begin activation: - for (auto info : libs_to_build) { - activate_more(*info); + for (auto lib : leaf_libs_to_build) { + activate_more(neo::into(libs_to_build), all_libs, *lib); } // Create package plans for each library and the package it owns: std::map pkg_plans; From 8d23858e7714f30084d95b5bf892dbce7a67a424 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 18 Jun 2022 21:34:18 -0600 Subject: [PATCH 49/62] Windows fs::path is not convertible to string --- src/bpt/cli/options.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index e8aed8b3..429f136b 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -509,7 +509,8 @@ int cli::options::default_from_env(std::string key, int def) noexcept { } cli::options::options() noexcept { - crs_cache_dir = bpt::getenv("BPT_CRS_CACHE_DIR", [] { return crs::cache::default_path(); }); + crs_cache_dir + = bpt::getenv("BPT_CRS_CACHE_DIR", [] { return crs::cache::default_path().string(); }); auto ll = getenv("BPT_LOG_LEVEL"); if (ll.has_value()) { From c7d4b92169741543ec0353f2cab09aa1a7ea77ec Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 18 Jun 2022 21:47:02 -0600 Subject: [PATCH 50/62] Fix: Load dependenceis for tests --- src/bpt/build/builder.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index 57728ed0..8543deca 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -74,7 +74,7 @@ static void activate_more(neo::output> libs_to_bu if (not did_insert) { return; } - for (crs::dependency const& dep : inf.lib.dependencies) { + auto add_dep = [&](const crs::dependency& dep) { for (bpt::name const& used_name : dep.uses) { auto found = all_libs.find(lm::usage{dep.name.str, used_name.str}); neo_assert(invariant, @@ -85,6 +85,14 @@ static void activate_more(neo::output> libs_to_bu used_name); activate_more(libs_to_build, all_libs, found->second); } + }; + for (crs::dependency const& dep : inf.lib.dependencies) { + add_dep(dep); + } + if (inf.sdt.params.build_tests) { + for (crs::dependency const& dep : inf.lib.test_dependencies) { + add_dep(dep); + } } } From d6e1d28e2b8efb97f8905421bd0cabdd00ae5f21 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 18 Jun 2022 21:48:58 -0600 Subject: [PATCH 51/62] MSVC can no longer handle noexcept(requires{}) --- src/bpt/build/plan/full.cpp | 5 +++-- src/bpt/cli/cmd/build_common.cpp | 5 +++-- src/bpt/cli/cmd/build_deps.cpp | 4 ++-- src/bpt/cli/cmd/new.cpp | 3 ++- src/bpt/cli/cmd/repo_validate.cpp | 3 ++- src/bpt/crs/cache_db.cpp | 3 ++- src/bpt/project/project.cpp | 7 ++++--- src/bpt/project/spdx.cpp | 4 ++-- src/bpt/sdist/root.cpp | 11 ++++++----- src/bpt/solve/solve.cpp | 13 +++++++------ src/bpt/util/siphash.test.cpp | 2 ++ src/bpt/util/tl.hpp | 15 +++++++++++++++ src/libman/library.cpp | 7 ++++--- 13 files changed, 54 insertions(+), 28 deletions(-) create mode 100644 src/bpt/util/tl.hpp diff --git a/src/bpt/build/plan/full.cpp b/src/bpt/build/plan/full.cpp index 9ff2b180..77a126ba 100644 --- a/src/bpt/build/plan/full.cpp +++ b/src/bpt/build/plan/full.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -78,8 +79,8 @@ void build_plan::compile_files(const build_env& env, // Make an error if there are any unmarked files auto missing_files = as_pending // - | ranges::views::filter(NEO_TL(!_1.marked)) - | ranges::views::transform(NEO_TL(e_nonesuch{_1.filepath.string(), std::nullopt})) + | ranges::views::filter(BPT_TL(!_1.marked)) + | ranges::views::transform(BPT_TL(e_nonesuch{_1.filepath.string(), std::nullopt})) | ranges::to_vector; if (!missing_files.empty()) { diff --git a/src/bpt/cli/cmd/build_common.cpp b/src/bpt/cli/cmd/build_common.cpp index 6c67bb37..8294acc1 100644 --- a/src/bpt/cli/cmd/build_common.cpp +++ b/src/bpt/cli/cmd/build_common.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -50,12 +51,12 @@ builder bpt::cli::create_project_builder(const bpt::cli::options& opts) { builder builder; if (!opts.build.built_json.has_value()) { - auto crs_deps = proj_sd.pkg.libraries | std::views::transform(NEO_TL(_1.dependencies)) + auto crs_deps = proj_sd.pkg.libraries | std::views::transform(BPT_TL(_1.dependencies)) | std::views::join | neo::to_vector; if (opts.build.want_tests) { extend(crs_deps, - proj_sd.pkg.libraries | std::views::transform(NEO_TL(_1.test_dependencies)) + proj_sd.pkg.libraries | std::views::transform(BPT_TL(_1.test_dependencies)) | std::views::join); } diff --git a/src/bpt/cli/cmd/build_deps.cpp b/src/bpt/cli/cmd/build_deps.cpp index 3c358208..67a2d8dd 100644 --- a/src/bpt/cli/cmd/build_deps.cpp +++ b/src/bpt/cli/cmd/build_deps.cpp @@ -9,9 +9,9 @@ #include #include #include +#include #include -#include #include #include #include @@ -46,7 +46,7 @@ static int _build_deps(const options& opts) { neo::ranges::range_of auto cli_deps = std::views::transform(opts.build_deps.deps, - NEO_TL(bpt::project_dependency::from_shorthand_string(_1) + BPT_TL(bpt::project_dependency::from_shorthand_string(_1) .as_crs_dependency())); neo::ranges::range_of auto all_deps diff --git a/src/bpt/cli/cmd/new.cpp b/src/bpt/cli/cmd/new.cpp index ae7c5993..6d842e28 100644 --- a/src/bpt/cli/cmd/new.cpp +++ b/src/bpt/cli/cmd/new.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -45,7 +46,7 @@ std::string get_argument(std::string_view prompt, std::string to_ident(std::string_view given) { std::string ret; - std::ranges::replace_copy_if(given, std::back_inserter(ret), NEO_TL(!std::isalnum(_1)), '_'); + std::ranges::replace_copy_if(given, std::back_inserter(ret), BPT_TL(!std::isalnum(_1)), '_'); if (!ret.empty() && std::isdigit(ret.front())) { ret.insert(ret.begin(), '_'); } diff --git a/src/bpt/cli/cmd/repo_validate.cpp b/src/bpt/cli/cmd/repo_validate.cpp index 491ecc03..02cebaef 100644 --- a/src/bpt/cli/cmd/repo_validate.cpp +++ b/src/bpt/cli/cmd/repo_validate.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,7 @@ static bool try_it(const crs::package_info& pkg, crs::cache_db& cache) { auto dep = {crs::dependency{ .name = pkg.id.name, .acceptable_versions = crs::version_range_set{pkg.id.version, pkg.id.version.next_after()}, - .uses = pkg.libraries | std::views::transform(NEO_TL(_1.name)) | neo::to_vector, + .uses = pkg.libraries | std::views::transform(BPT_TL(_1.name)) | neo::to_vector, }}; return bpt_leaf_try { fmt::print("Validate package .br.cyan[{}] ..."_styled, pkg.id.to_string()); diff --git a/src/bpt/crs/cache_db.cpp b/src/bpt/crs/cache_db.cpp index 7f049069..45886c9a 100644 --- a/src/bpt/crs/cache_db.cpp +++ b/src/bpt/crs/cache_db.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -241,7 +242,7 @@ bool should_revalidate(std::string_view cache_control, steady_time_point resourc // Always revalidate return true; } - if (auto max_age = std::ranges::find_if(parts, NEO_TL(_1.starts_with("max-age="))); + if (auto max_age = std::ranges::find_if(parts, BPT_TL(_1.starts_with("max-age="))); max_age != parts.end()) { auto age_str = bpt::trim_view(max_age->substr(std::strlen("max-age="))); int max_age_int = 0; diff --git a/src/bpt/project/project.cpp b/src/bpt/project/project.cpp index d518dfce..34501834 100644 --- a/src/bpt/project/project.cpp +++ b/src/bpt/project/project.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -74,16 +75,16 @@ crs::package_info project_manifest::as_crs_package_meta() const noexcept { .test_dependencies = {}, }); extend(ret.libraries.back().dependencies, - root_dependencies | std::views::transform(NEO_TL(_1.as_crs_dependency()))); + root_dependencies | std::views::transform(BPT_TL(_1.as_crs_dependency()))); extend(ret.libraries.back().test_dependencies, - root_test_dependencies | std::views::transform(NEO_TL(_1.as_crs_dependency()))); + root_test_dependencies | std::views::transform(BPT_TL(_1.as_crs_dependency()))); } auto meta_obj = json5::data::object_type(); if (authors) { meta_obj.emplace("authors", *authors // - | std::views::transform(NEO_TL(json5::data(_1))) // + | std::views::transform(BPT_TL(json5::data(_1))) // | neo::to_vector); } if (description) { diff --git a/src/bpt/project/spdx.cpp b/src/bpt/project/spdx.cpp index a769ee5f..1c00d162 100644 --- a/src/bpt/project/spdx.cpp +++ b/src/bpt/project/spdx.cpp @@ -2,12 +2,12 @@ #include #include +#include #include #include #include #include -#include #include #include @@ -61,7 +61,7 @@ std::string_view next_token(std::string_view sv) { template neo::opt_ref find_with_id(std::string_view id) { - auto found = std::ranges::lower_bound(T::all, id, std::less<>{}, NEO_TL(_1.id)); + auto found = std::ranges::lower_bound(T::all, id, std::less<>{}, BPT_TL(_1.id)); if (found == std::ranges::end(T::all) || found->id != id) { return std::nullopt; } diff --git a/src/bpt/sdist/root.cpp b/src/bpt/sdist/root.cpp index d9ecea16..6288ea90 100644 --- a/src/bpt/sdist/root.cpp +++ b/src/bpt/sdist/root.cpp @@ -1,11 +1,12 @@ #include "./root.hpp" +#include + #include #include #include #include -#include using namespace bpt; @@ -23,10 +24,10 @@ bpt::collected_sources bpt::collect_sources(path_ref dirpath) { auto state = neo::copy_shared(collector_state{dirpath, fs::recursive_directory_iterator{dirpath}}); return state->dir_iter // - | filter(NEO_TL(_1.is_regular_file())) // - | transform([state] NEO_CTL(source_file::from_path(_1, state->base_path))) // - | filter(NEO_TL(_1.has_value())) // - | transform([state] NEO_CTL(source_file{std::move(*_1)})) // + | filter(BPT_TL(_1.is_regular_file())) // + | transform([state] BPT_CTL(source_file::from_path(_1, state->base_path))) // + | filter(BPT_TL(_1.has_value())) // + | transform([state] BPT_CTL(source_file{std::move(*_1)})) // ; } diff --git a/src/bpt/solve/solve.cpp b/src/bpt/solve/solve.cpp index b4efbc0e..ad7d5220 100644 --- a/src/bpt/solve/solve.cpp +++ b/src/bpt/solve/solve.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -155,7 +156,7 @@ struct metadata_provider { .first; sr::sort(found->second, std::less<>{}, - NEO_TL(std::make_tuple(_1.pkg.id.version, -_1.pkg.id.revision))); + BPT_TL(std::make_tuple(_1.pkg.id.version, -_1.pkg.id.revision))); } return found->second; } @@ -169,7 +170,7 @@ struct metadata_provider { return false; } bool has_all_libraries = sr::all_of(req.uses, [&](auto&& uses_name) { - return sr::any_of(entry.pkg.libraries, NEO_TL(uses_name == _1.name)); + return sr::any_of(entry.pkg.libraries, BPT_TL(uses_name == _1.name)); }); if (!has_all_libraries) { bpt_log(debug, @@ -234,9 +235,9 @@ struct metadata_provider { auto reqs = pkg.libraries // | stdv::filter([&](auto&& lib) { return uses.contains(lib.name); }) // - | stdv::transform(NEO_TL(_1.dependencies)) // + | stdv::transform(BPT_TL(_1.dependencies)) // | stdv::join // - | stdv::transform(NEO_TL(requirement::from_crs_dep(_1))) // + | stdv::transform(BPT_TL(requirement::from_crs_dep(_1))) // | neo::to_vector; for (auto&& r : reqs) { bpt_log(trace, " Requires: {}", r.decl_to_string()); @@ -358,7 +359,7 @@ void try_load_nonesuch_packages(boost::leaf::error_id error, std::vector bpt::solve(crs::cache_db const& cache, neo::any_input_range deps_) { metadata_provider provider{cache}; - auto deps = deps_ | stdv::transform(NEO_TL(requirement::from_crs_dep(_1))) | neo::to_vector; + auto deps = deps_ | stdv::transform(BPT_TL(requirement::from_crs_dep(_1))) | neo::to_vector; auto sln = bpt_leaf_try { return pubgrub::solve(deps, provider); } bpt_leaf_catch(catch_ exc)->noreturn_t { auto error = boost::leaf::new_error(); @@ -369,7 +370,7 @@ std::vector bpt::solve(crs::cache_db const& cache, BPT_ERR_REF("dep-res-failure")); }; return sln - | stdv::transform(NEO_TL(crs::pkg_id{ + | stdv::transform(BPT_TL(crs::pkg_id{ .name = _1.name, .version = sole_version(_1.versions), .revision = _1.pkg_version.value(), diff --git a/src/bpt/util/siphash.test.cpp b/src/bpt/util/siphash.test.cpp index 0786b2dd..56ea2e5e 100644 --- a/src/bpt/util/siphash.test.cpp +++ b/src/bpt/util/siphash.test.cpp @@ -2,6 +2,8 @@ #include +#include + const std::uint64_t vectors_sip64[64] = { {0x310e0edd47db6f72}, {0xfd67dc93c539f874}, {0x5a4fa9d909806c0d}, {0x2d7efbd796666785}, {0xb7877127e09427cf}, {0x8da699cd64557618}, {0xcee3fe586e46c9cb}, {0x37d1018bf50002ab}, diff --git a/src/bpt/util/tl.hpp b/src/bpt/util/tl.hpp new file mode 100644 index 00000000..c023ed04 --- /dev/null +++ b/src/bpt/util/tl.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#define BPT_CTL(...) \ + (TlArgs && ... _args) \ + ->decltype(auto) requires(NEO_TL_REQUIRES(__VA_ARGS__)) { \ + [[maybe_unused]] auto&& _1 = ::neo::tl_detail::nth_arg<0>(NEO_FWD(_args)...); \ + [[maybe_unused]] auto&& _2 = ::neo::tl_detail::nth_arg<1>(NEO_FWD(_args)...); \ + [[maybe_unused]] auto&& _3 = ::neo::tl_detail::nth_arg<2>(NEO_FWD(_args)...); \ + [[maybe_unused]] auto&& _4 = ::neo::tl_detail::nth_arg<3>(NEO_FWD(_args)...); \ + return (__VA_ARGS__); \ + } + +#define BPT_TL [&] BPT_CTL diff --git a/src/libman/library.cpp b/src/libman/library.cpp index 21bd1651..f31d2d9b 100644 --- a/src/libman/library.cpp +++ b/src/libman/library.cpp @@ -1,10 +1,11 @@ #include "./library.hpp" +#include + #include #include #include -#include using namespace lm; @@ -23,8 +24,8 @@ bpt::result library::from_file(path_ref fpath) { read_opt("Path", ret.linkable_path), read_accumulate("Include-Path", ret.include_paths), read_accumulate("Preprocessor-Define", ret.preproc_defs), - read_accumulate("Uses", ret.uses, NEO_TL(split_usage_string(_1).value())), - read_accumulate("Links", ret.links, NEO_TL(split_usage_string(_1).value())), + read_accumulate("Uses", ret.uses, BPT_TL(split_usage_string(_1).value())), + read_accumulate("Links", ret.links, BPT_TL(split_usage_string(_1).value())), read_accumulate("Special-Uses", ret.special_uses)); } catch (const boost::leaf::bad_result& err) { return err.load(); From 87c401da7e2042a7cb78dc66a56f8317a29dd864 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 19 Jun 2022 19:12:46 -0600 Subject: [PATCH 52/62] Bump Alpine version and GCC within it --- tools/Dockerfile.alpine | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Dockerfile.alpine b/tools/Dockerfile.alpine index 0964e49f..41cb209e 100644 --- a/tools/Dockerfile.alpine +++ b/tools/Dockerfile.alpine @@ -1,7 +1,7 @@ -FROM alpine:3.13.1 +FROM alpine:3.15.4 # Base build dependencies -RUN apk add "gcc=10.2.1_pre1-r3" "g++=10.2.1_pre1-r3" make python3 py3-pip \ +RUN apk add "gcc~10.3" "g++~10.3" make python3 py3-pip \ git openssl-libs-static openssl-dev ccache lld curl python3-dev cmake clang # We use version-qualified names for compiler executables From daa86f5e62b21ace9a96e108799adb1cf6f688cc Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sun, 19 Jun 2022 19:23:16 -0600 Subject: [PATCH 53/62] We need DECAY_COPY --- src/bpt/util/copy.hpp | 16 ++++++++++++++++ src/libman/library.cpp | 11 ++++++++--- 2 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 src/bpt/util/copy.hpp diff --git a/src/bpt/util/copy.hpp b/src/bpt/util/copy.hpp new file mode 100644 index 00000000..7d8615d4 --- /dev/null +++ b/src/bpt/util/copy.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include + +#include +#include + +namespace bpt { + +template +constexpr std::decay_t +decay_copy(T&& arg) noexcept requires std::constructible_from, T &&> { + return static_cast>(NEO_FWD(arg)); +} + +} // namespace bpt diff --git a/src/libman/library.cpp b/src/libman/library.cpp index f31d2d9b..e61ffe70 100644 --- a/src/libman/library.cpp +++ b/src/libman/library.cpp @@ -1,10 +1,11 @@ #include "./library.hpp" +#include +#include #include #include -#include #include using namespace lm; @@ -24,8 +25,12 @@ bpt::result library::from_file(path_ref fpath) { read_opt("Path", ret.linkable_path), read_accumulate("Include-Path", ret.include_paths), read_accumulate("Preprocessor-Define", ret.preproc_defs), - read_accumulate("Uses", ret.uses, BPT_TL(split_usage_string(_1).value())), - read_accumulate("Links", ret.links, BPT_TL(split_usage_string(_1).value())), + read_accumulate("Uses", + ret.uses, + BPT_TL(bpt::decay_copy(split_usage_string(_1).value()))), + read_accumulate("Links", + ret.links, + BPT_TL(bpt::decay_copy(split_usage_string(_1).value()))), read_accumulate("Special-Uses", ret.special_uses)); } catch (const boost::leaf::bad_result& err) { return err.load(); From 12e8538c456f24d86f77a77a7d0a1312949961d6 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 20:54:26 -0600 Subject: [PATCH 54/62] Handle invalid toolchain option keys properly --- src/bpt/cli/error_handler.cpp | 11 ++++ src/bpt/toolchain/from_json.cpp | 111 +++++++++++++++----------------- src/bpt/toolchain/from_json.hpp | 5 ++ 3 files changed, 67 insertions(+), 60 deletions(-) diff --git a/src/bpt/cli/error_handler.cpp b/src/bpt/cli/error_handler.cpp index 64bdf3e3..6668c8f2 100644 --- a/src/bpt/cli/error_handler.cpp +++ b/src/bpt/cli/error_handler.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -169,6 +170,16 @@ auto handlers = std::tuple( // write_error_marker("bad-toolchain"); return 1; }, + [](e_bad_toolchain_key nonesuch, e_loading_toolchain, e_toolchain_filepath* tc_file) { + nonesuch.log_error("Unknown toolchain option: '.br.red[{}]'"_styled); + if (tc_file) { + bpt_log(error, + " (While reading toolchain from file [.bold.yellow[{}]])"_styled, + tc_file->value); + } + write_error_marker("bad-toolchain-opt"); + return 1; + }, [](e_name_str badname, invalid_name_reason why, e_parse_dep_range_shorthand_string depstr, diff --git a/src/bpt/toolchain/from_json.cpp b/src/bpt/toolchain/from_json.cpp index 6e26a76f..ffc7cee5 100644 --- a/src/bpt/toolchain/from_json.cpp +++ b/src/bpt/toolchain/from_json.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,7 @@ toolchain bpt::parse_toolchain_json5(std::string_view j5_str, std::string_view c toolchain bpt::parse_toolchain_json_data(const json5::data& dat, std::string_view context) { using namespace semester; + using namespace bpt::walk_utils; opt_string compiler_id; opt_string c_compiler; @@ -118,20 +120,59 @@ toolchain bpt::parse_toolchain_json_data(const json5::data& dat, std::string_vie }; }; -#define KEY_EXTEND_FLAGS(Name) \ - if_key { #Name, extend_flags(#Name, Name) } +#define KEY_EXTEND_FLAGS(Name) if_key{#Name, extend_flags(#Name, Name)} #define KEY_STRING(Name) \ - if_key{ \ - #Name, \ - require_type("`" #Name "` must be a string"), \ - put_into{Name}, \ - } + if_key { #Name, require_type < string>("`" #Name "` must be a string"), put_into{Name }, } + + key_dym_tracker base_dym{{ + "compiler_id", + "c_compiler", + "cxx_compiler", + "c_version", + "cxx_version", + "c_flags", + "cxx_flags", + "warning_flags", + "link_flags", + "flags", + "debug", + "optimize", + "runtime", + }}; + + key_dym_tracker adv_dym{{ + "deps_mode", + "include_template", + "external_include_template", + "define_template", + "base_warning_flags", + "base_flags", + "base_c_flags", + "base_cxx_flags", + "c_compile_file", + "cxx_compile_file", + "create_archive", + "link_executable", + "obj_prefix", + "obj_suffix", + "archive_prefix", + "archive_suffix", + "exe_prefix", + "exe_suffix", + "tty_flags", + "lang_version_flag_template", + "c_source_type_flags", + "cxx_source_type_flags", + "syntax_only_flags", + "consider_env", + }}; walk( // dat, require_type("Root of toolchain data must be a mapping"), mapping{ + base_dym.tracker(), if_key{"$schema", just_accept}, KEY_STRING(compiler_id), KEY_STRING(c_compiler), @@ -163,6 +204,7 @@ toolchain bpt::parse_toolchain_json_data(const json5::data& dat, std::string_vie "advanced", require_type("`advanced` must be a mapping"), mapping{ + adv_dym.tracker(), if_key{"deps_mode", require_type("`deps_mode` must be a string"), put_into{deps_mode_str}}, @@ -189,61 +231,10 @@ toolchain bpt::parse_toolchain_json_data(const json5::data& dat, std::string_vie KEY_EXTEND_FLAGS(cxx_source_type_flags), KEY_EXTEND_FLAGS(syntax_only_flags), KEY_EXTEND_FLAGS(consider_env), - [&](auto key, auto) -> walk_result { - auto dym = did_you_mean(key, - { - "deps_mode", - "include_template", - "external_include_template", - "define_template", - "base_warning_flags", - "base_flags", - "base_c_flags", - "base_cxx_flags", - "c_compile_file", - "cxx_compile_file", - "create_archive", - "link_executable", - "obj_prefix", - "obj_suffix", - "archive_prefix", - "archive_suffix", - "exe_prefix", - "exe_suffix", - "tty_flags", - "lang_version_flag_template", - "c_source_type_flags", - "cxx_source_type_flags", - "syntax_only_flags", - "consider_env", - }); - fail(context, - "Unknown toolchain advanced-config key ‘{}’ (Did you mean ‘{}’?)", - key, - *dym); - }, + adv_dym.rejecter(), }, }, - [&](auto key, auto&&) -> walk_result { - // They've given an unknown key. Ouch. - auto dym = did_you_mean(key, - { - "compiler_id", - "c_compiler", - "cxx_compiler", - "c_version", - "cxx_version", - "c_flags", - "cxx_flags", - "warning_flags", - "link_flags", - "flags", - "debug", - "optimize", - "runtime", - }); - fail(context, "Unknown toolchain config key ‘{}’ (Did you mean ‘{}’?)", key, *dym); - }, + base_dym.rejecter(), }); if (debug_str.has_value() && debug_str != "embedded" && debug_str != "split" diff --git a/src/bpt/toolchain/from_json.hpp b/src/bpt/toolchain/from_json.hpp index a2d259d5..53802edc 100644 --- a/src/bpt/toolchain/from_json.hpp +++ b/src/bpt/toolchain/from_json.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -8,6 +9,10 @@ namespace bpt { +struct e_bad_toolchain_key : e_nonesuch { + using e_nonesuch::e_nonesuch; +}; + toolchain parse_toolchain_json5(std::string_view json5, std::string_view context = "Loading toolchain JSON"); From 634e928534973181ccb66437c9235cad4e5e76d3 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 20:54:41 -0600 Subject: [PATCH 55/62] Support printing of e_nonesuch for LEAF --- src/bpt/error/nonesuch.cpp | 9 +++++++++ src/bpt/error/nonesuch.hpp | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/src/bpt/error/nonesuch.cpp b/src/bpt/error/nonesuch.cpp index a5c8b2f2..4f221b29 100644 --- a/src/bpt/error/nonesuch.cpp +++ b/src/bpt/error/nonesuch.cpp @@ -4,6 +4,8 @@ #include +#include + using namespace bpt; using namespace fansi::literals; @@ -13,3 +15,10 @@ void e_nonesuch::log_error(std::string_view fmt) const noexcept { bpt_log(error, " (Did you mean '.br.yellow[{}]'?)"_styled, *nearest); } } + +void bpt::e_nonesuch::ostream_into(std::ostream& out) const noexcept { + out << "bpt::e_nonsuch: Given " << std::quoted(given); + if (nearest.has_value()) { + out << " (nearest is " << std::quoted(*nearest) << ")"; + } +} \ No newline at end of file diff --git a/src/bpt/error/nonesuch.hpp b/src/bpt/error/nonesuch.hpp index a02824c9..968b0651 100644 --- a/src/bpt/error/nonesuch.hpp +++ b/src/bpt/error/nonesuch.hpp @@ -3,6 +3,8 @@ #include #include +#include + namespace bpt { struct e_nonesuch { @@ -14,6 +16,13 @@ struct e_nonesuch { , nearest{nr} {} void log_error(std::string_view fmt) const noexcept; + + void ostream_into(std::ostream& out) const noexcept; + + friend std::ostream& operator<<(std::ostream& out, const e_nonesuch& self) noexcept { + self.ostream_into(out); + return out; + } }; } // namespace bpt From fd8e7e9c5f3738d97b568a29becd9d7a3ea11ca2 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 20:55:50 -0600 Subject: [PATCH 56/62] Fix loading of sibling libraries from test-dependencies --- src/bpt/build/builder.cpp | 13 +++++++++++++ tests/test_uses/the_test_dependency/bpt.yaml | 10 ++++++++-- .../include/the_test_dependency_24fe5647.hpp | 2 ++ .../the_test_dependency/sibling/src/test-sibling.h | 1 + 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 tests/test_uses/the_test_dependency/sibling/src/test-sibling.h diff --git a/src/bpt/build/builder.cpp b/src/bpt/build/builder.cpp index 8543deca..f06cd0f8 100644 --- a/src/bpt/build/builder.cpp +++ b/src/bpt/build/builder.cpp @@ -86,13 +86,26 @@ static void activate_more(neo::output> libs_to_bu activate_more(libs_to_build, all_libs, found->second); } }; + auto add_siblings = [&](const name& sibling_name) { + auto sibling = all_libs.find(lm::usage{inf.pkg.id.name.str, sibling_name.str}); + neo_assert(invariant, + sibling != all_libs.end(), + "Failed to find sibling library for 'using'"); + activate_more(libs_to_build, all_libs, sibling->second); + }; for (crs::dependency const& dep : inf.lib.dependencies) { add_dep(dep); } + for (name const& use : inf.lib.intra_using) { + add_siblings(use); + } if (inf.sdt.params.build_tests) { for (crs::dependency const& dep : inf.lib.test_dependencies) { add_dep(dep); } + for (const name& use : inf.lib.intra_test_using) { + add_siblings(use); + } } } diff --git a/tests/test_uses/the_test_dependency/bpt.yaml b/tests/test_uses/the_test_dependency/bpt.yaml index e53ce40b..bc195b0d 100644 --- a/tests/test_uses/the_test_dependency/bpt.yaml +++ b/tests/test_uses/the_test_dependency/bpt.yaml @@ -1,4 +1,10 @@ { - name: 'the_test_dependency', - version: '0.0.0', + name: "the_test_dependency", + version: "0.0.0", + + libraries: + [ + { path: ., name: "the_test_dependency", using: [sibling] }, + { path: sibling, name: sibling }, + ], } diff --git a/tests/test_uses/the_test_dependency/include/the_test_dependency_24fe5647.hpp b/tests/test_uses/the_test_dependency/include/the_test_dependency_24fe5647.hpp index 4554dcf4..5f8f4a58 100644 --- a/tests/test_uses/the_test_dependency/include/the_test_dependency_24fe5647.hpp +++ b/tests/test_uses/the_test_dependency/include/the_test_dependency_24fe5647.hpp @@ -1,5 +1,7 @@ #pragma once +#include + namespace the_test_dependency { inline bool some_fn() { return true; } } // namespace the_test_dependency diff --git a/tests/test_uses/the_test_dependency/sibling/src/test-sibling.h b/tests/test_uses/the_test_dependency/sibling/src/test-sibling.h new file mode 100644 index 00000000..fefa00ad --- /dev/null +++ b/tests/test_uses/the_test_dependency/sibling/src/test-sibling.h @@ -0,0 +1 @@ +// This file is intentionally left blank \ No newline at end of file From 706fcaee3ccca35e45fa13229ec1b7c558fe6904 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 20:56:15 -0600 Subject: [PATCH 57/62] Support YAML toolchain files --- src/bpt/cli/options.cpp | 2 +- src/bpt/toolchain/toolchain.cpp | 27 +++++++++++++++++++++++---- src/bpt/toolchain/toolchain.hpp | 1 + 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/bpt/cli/options.cpp b/src/bpt/cli/options.cpp index 429f136b..890b86f2 100644 --- a/src/bpt/cli/options.cpp +++ b/src/bpt/cli/options.cpp @@ -473,7 +473,7 @@ toolchain bpt::cli::options::load_toolchain() const { return bpt::toolchain::get_builtin(default_tc); } else { BPT_E_SCOPE(bpt::e_toolchain_filepath{tc_str}); - return parse_toolchain_json5(bpt::read_file(tc_str)); + return toolchain::from_file(fs::path(tc_str)); } } diff --git a/src/bpt/toolchain/toolchain.cpp b/src/bpt/toolchain/toolchain.cpp index 0aad9281..861edb29 100644 --- a/src/bpt/toolchain/toolchain.cpp +++ b/src/bpt/toolchain/toolchain.cpp @@ -13,9 +13,12 @@ #include #include #include +#include +#include #include #include +#include #include #include @@ -334,6 +337,9 @@ toolchain toolchain::get_builtin(const std::string_view tc_id_) { } bpt::toolchain bpt::toolchain::get_default() { + using namespace std::literals; + auto dirs = {fs::current_path(), bpt_config_dir(), user_home_dir()}; + auto extensions = {".yaml", ".jsonc", ".json5", ".json"}; auto candidates = { fs::current_path() / "toolchain.json5", fs::current_path() / "toolchain.jsonc", @@ -345,14 +351,27 @@ bpt::toolchain bpt::toolchain::get_default() { user_home_dir() / "toolchain.jsonc", user_home_dir() / "toolchain.json", }; - for (auto&& cand : candidates) { + for (auto&& [ext, dir] : ranges::view::cartesian_product(extensions, dirs)) { + fs::path cand = dir / ("toolchain"s + ext); bpt_log(trace, "Checking for default toolchain at [{}]", cand.string()); - if (fs::exists(cand)) { - bpt_log(debug, "Using default toolchain file: {}", cand.string()); - return parse_toolchain_json5(bpt::read_file(cand)); + if (not fs::is_regular_file(cand)) { + continue; } + bpt_log(debug, "Using default toolchain file: {}", cand.string()); + return toolchain::from_file(cand); } BOOST_LEAF_THROW_EXCEPTION(e_human_message{neo::ufmt("No default toolchain")}, BPT_ERR_REF("no-default-toolchain"), e_error_marker{"no-default-toolchain"}); } + +toolchain toolchain::from_file(path_ref fpath) { + if (fpath.extension().string() == ".yaml") { + auto node = bpt::parse_yaml_file(fpath); + auto data = bpt::yaml_as_json5_data(node); + return parse_toolchain_json_data(data, + neo::ufmt("Loading toolchain from [{}]", fpath.string())); + } else { + return parse_toolchain_json5(bpt::read_file(fpath)); + } +} \ No newline at end of file diff --git a/src/bpt/toolchain/toolchain.hpp b/src/bpt/toolchain/toolchain.hpp index a189013c..bca3b937 100644 --- a/src/bpt/toolchain/toolchain.hpp +++ b/src/bpt/toolchain/toolchain.hpp @@ -106,6 +106,7 @@ class toolchain { static toolchain get_builtin(std::string_view key); static toolchain get_default(); + static toolchain from_file(path_ref fpath); }; } // namespace bpt From 9e2d3a00372070b2f27dd537aa0519972d8d5eb9 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 21:41:36 -0600 Subject: [PATCH 58/62] Drop the deploy stage --- azure-pipelines.yml | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 06d6c062..06606f48 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,10 +1,5 @@ # Refer: https://aka.ms/yaml -variables: - shouldDeploy: >- - ${{ eq(variables['Build.SourceBranch'], 'refs/heads/master') }} - deployDest: ${{ format('~/web/{0}/', variables['Build.SourceBranchName']) }} - stages: - stage: build_test displayName: Build and Test @@ -81,29 +76,3 @@ stages: - publish: _build/bpt-macos-x64 displayName: Publish artifact: bpt-macos-x64 - - - stage: deploy_build - displayName: Deploy - condition: and(succeeded(), eq(variables.shouldDeploy, 'true')) - jobs: - - job: deploy - displayName: Deploy (${{variables['Build.SourceBranch']}}) - steps: - - checkout: none - - task: DownloadPipelineArtifact@2 - displayName: Download builds - inputs: - targetPath: art-dirs/ - - bash: | - set -eu - mkdir -p art/ - mv -- $(find art-dirs/ -type f) art/ - displayName: Rearrange - - task: CopyFilesOverSSH@0 - displayName: Post builds - inputs: - sshEndpoint: dds.pizza - sourceFolder: art/ - targetFolder: ${{ variables.deployDest }} - failOnEmptySource: true - overwrite: true From 83b236832a17cfd51bfee48c9c17c681420ccd62 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 21:44:07 -0600 Subject: [PATCH 59/62] Remaining references to dds.pizza --- docs/guide/remote-pkgs.rst | 14 +++++++------- docs/tut/install.rst | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/guide/remote-pkgs.rst b/docs/guide/remote-pkgs.rst index afdf81f3..60360912 100644 --- a/docs/guide/remote-pkgs.rst +++ b/docs/guide/remote-pkgs.rst @@ -51,19 +51,19 @@ obtained with the :ref:`cli.pkg-search` subcommand:: Name: abseil Versions: 2018.6.0, 2019.8.8, 2020.2.25 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza Name: asio Versions: 1.12.0, 1.12.1, 1.12.2, 1.13.0, 1.14.0, 1.14.1, 1.16.0, 1.16.1 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza Name: boost.leaf Versions: 0.1.0, 0.2.0, 0.2.1, 0.2.2, 0.2.3, 0.2.4, 0.2.5, 0.3.0 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza Name: boost.mp11 Versions: 1.70.0, 1.71.0, 1.72.0, 1.73.0 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza Optionally, one can search with a fnmatch-style pattern:: @@ -71,15 +71,15 @@ Optionally, one can search with a fnmatch-style pattern:: Name: neo-buffer Versions: 0.2.1, 0.3.0, 0.4.0, 0.4.1, 0.4.2 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza Name: neo-compress Versions: 0.1.0, 0.1.1, 0.2.0 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza Name: neo-concepts Versions: 0.2.2, 0.3.0, 0.3.1, 0.3.2, 0.4.0 - From: repo-1.dds.pizza + From: repo-1.bpt.pizza .. note:: diff --git a/docs/tut/install.rst b/docs/tut/install.rst index 6a4100b6..e306da6a 100644 --- a/docs/tut/install.rst +++ b/docs/tut/install.rst @@ -20,17 +20,17 @@ command-line with an easy-to-remember URL. Using ``curl``: .. code-block:: bash # For Linux, writes a file in the working directory called "bpt" - curl dds.pizza/get/linux -Lo bpt + curl bpt.pizza/get/linux -Lo bpt # For macOS, writes a file in the working directory called "bpt" - curl dds.pizza/get/macos -Lo bpt + curl bpt.pizza/get/macos -Lo bpt Or using PowerShell: .. code-block:: powershell # Writes a file in the working directory called "bpt.exe" - Invoke-WebRequest dds.pizza/get/windows -OutFile bpt.exe + Invoke-WebRequest bpt.pizza/get/windows -OutFile bpt.exe .. note:: From fd5c274d8466e6ceb07f0330b0dd89ea4d11181c Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 22:49:53 -0600 Subject: [PATCH 60/62] Use LTO on the static Linux build --- tools/bpt_ci/toolchain.py | 8 +++++--- tools/gcc-10-static-rel.jsonc | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/bpt_ci/toolchain.py b/tools/bpt_ci/toolchain.py index 25657ce3..23b4b12f 100644 --- a/tools/bpt_ci/toolchain.py +++ b/tools/bpt_ci/toolchain.py @@ -2,7 +2,7 @@ import sys from contextlib import contextmanager from pathlib import Path -from typing import Iterator, Mapping, MutableSequence +from typing import Iterator, Mapping, MutableSequence, cast import json5 @@ -25,8 +25,10 @@ def fixup_toolchain(json_file: Pathish) -> Iterator[Path]: if ccache and data.get('compiler_id') in ('gnu', 'clang'): data['compiler_launcher'] = [str(ccache)] # type: ignore # Check for lld for use with GCC/Clang - if paths.find_exe('ld.lld') and data.get('compiler_id') in ('gnu', 'clang'): - link_flags = data.setdefault('link_flags', []) + link_flags = cast('list[str]', data.setdefault('link_flags', [])) + assert isinstance(link_flags, list) and all(isinstance(flag, str) for flag in link_flags) + uses_lto = any(flag.startswith('-flto') for flag in link_flags) + if not uses_lto and paths.find_exe('ld.lld') and data.get('compiler_id') in ('gnu', 'clang'): assert isinstance(link_flags, MutableSequence), link_flags link_flags.append('-fuse-ld=lld') # Save the new toolchain data diff --git a/tools/gcc-10-static-rel.jsonc b/tools/gcc-10-static-rel.jsonc index 3a56d430..3aa4d7c2 100644 --- a/tools/gcc-10-static-rel.jsonc +++ b/tools/gcc-10-static-rel.jsonc @@ -13,13 +13,15 @@ "flags": [ "-fdata-sections", "-ffunction-sections", - "-Os" + "-Os", + "-flto", ], "link_flags": [ "-static", "-l:libssl.a", "-l:libcrypto.a", "-ldl", + "-flto=auto", // WORKAROUND: https://sourceware.org/legacy-ml/glibc-bugs/2018-09/msg00009.html "-Wl,-u,pthread_mutex_lock,-u,pthread_mutex_unlock,-u,pthread_self", "-Wl,--gc-sections,--strip-all" From eb75ef0da7b79f071de463f37c6f6956618b16af Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Wed, 22 Jun 2022 22:50:57 -0600 Subject: [PATCH 61/62] We don't prepare a site anymore --- .gitignore | 1 - Makefile | 7 -- site/index.html | 291 ------------------------------------------------ 3 files changed, 299 deletions(-) delete mode 100644 site/index.html diff --git a/.gitignore b/.gitignore index 907316f3..26358861 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ _build/ -_site/ __pycache__/ .vscode/ _prebuilt/ diff --git a/Makefile b/Makefile index 28f8f315..b35d69b0 100644 --- a/Makefile +++ b/Makefile @@ -79,10 +79,3 @@ vagrant-freebsd-ci: mkdir -p _build/ vagrant scp freebsd11:/vagrant/_build/bpt _build/bpt-freebsd-x64 vagrant halt - -site: docs - rm -r -f -- _site/ - mkdir -p _site/ - cp site/index.html _site/ - cp -r _build/docs _site/ - echo "Site generated at _site/" diff --git a/site/index.html b/site/index.html deleted file mode 100644 index 6bca3217..00000000 --- a/site/index.html +++ /dev/null @@ -1,291 +0,0 @@ - - - - - - - BPT - - - - - -
-
BPT - The Simplest
- -
-
-
-
BPT
-
Tooling for a new decade
-
-
-
- -
What is BPT?
-
- BPT is a new build, test, and packaging tool for native C and C++ - libraries and applications, with a focus on simplicity, speed, and - integratability. -
- -
What makes BPT different?
-
- Convention over configuration. -

- Traditional build tools have been built to cede all control to their - users. While this may sound appealing, it leads to rampant ecosystem - fragmentation that impedes the ability for us to compose our - libraries and tools. -

- BPT's approach is to trade this flexibility for something sorely lacking - in the C and C++ build and distribution ecosystem: Simplicity. -
- -
Does BPT replace [XYZ] build tool?
-
- While BPT is a build tool, it is not meant as a full replacement - for all use cases of other build tools (e.g. CMake and Meson). -

- For many use cases, BPT will serve as a possible replacement for more - flexible build systems, especially when the build itself is far simpler - than is warranted by the flexibility offered by those tools. -

- Additionally, BPT is built to augment other build tools. The - output from BPT can be fed into other build and packaging systems. -
- -
Does BPT replace [XYZ] packaging tool?
-
- Yes and no. -

- BPT supports dependency resolution, procurement, and building, much like - many other tools, but has a few important differences of opinion. Refer - to the documentation for more information. -
- -
Is BPT "production ready"?
-
- At the time of writing, BPT is still in its alpha stages, is missing - several end-goal features, and will have several breaking changes before - its first "1.0" release. -

- Even then, BPT is ready to be used for experiments, hobby projects, and - in any place that doesn't require stability. -
- -
Is BPT free?
-
- Yes! BPT and its source code are available free of charge. -
- -
Is BPT open source?
-
- Yes! -

- The main BPT codebase is licensed under the - Mozilla Public License Version 2.0, although it is built upon - many components variously licensed as MIT, BSD, Boost, and public domain. -
- -
What platforms are supported?
-
- BPT is built, tested, distributed, and supported on Windows, macOS, - Linux, and FreeBSD. -

- The Microsoft Visual C++, GNU GCC, LLVM/Clang, and AppleClang compilers - are all supported. -
- -
Is BPT centralized?
-
- No / "not yet" -

- BPT's package procurement is in very early stages, and there is no - centralized repository of packages available for download. -

- BPT maintains a local catalog database that contain instructions it can - use to obtain packages from the internet. At the moment, this involves - cloning a Git repository, but there are plans to support catalog updates - and source distributions delivered over HTTP(S) in the future. This - includes the ability to host private package repositories. -
-
- - - - - \ No newline at end of file From d549200c58887411a60d472e0e5d0c4d2e247ff0 Mon Sep 17 00:00:00 2001 From: vector-of-bool Date: Sat, 25 Jun 2022 18:46:02 -0600 Subject: [PATCH 62/62] Doc spelling grammar tweaks --- docs/conf.py | 3 --- docs/crs/index.rst | 2 +- docs/design.rst | 6 ++--- docs/dev/reqs.rst | 9 ++++--- docs/dev/testing.rst | 2 +- docs/guide/build-deps.rst | 8 +++--- docs/guide/cmake.rst | 11 ++++---- docs/guide/deps.rst | 6 +++++ docs/guide/terms.rst | 4 +++ docs/guide/toolchains.rst | 57 +++++++++++++++++++++++++-------------- docs/howto/cmake.rst | 10 +++---- 11 files changed, 71 insertions(+), 47 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 78fe1d9a..486bbb21 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -150,7 +150,6 @@ def add_target_and_index(self, name: tuple[_FullNameStr, _Ident], sig: str, sign self.state.document.note_explicit_target(signode) dom = cast(SchematicDomain, self.env.get_domain('schematic')) - print(f'Saving {self.objtype} {fullname}') assert self.objtype in ('property', 'mapping') dom.data['objects'][fullname] = { 'parent': _dotpath(self.env), @@ -391,7 +390,6 @@ def find_obj(self, node: addnodes.pending_xref, name: str) -> _SchematicEntry | else: partials = [name] for cand in partials: - print('Looking for fullnamed object:', cand) found = self.data['objects'].get(cand) if found is not None: return found @@ -400,7 +398,6 @@ def find_obj(self, node: addnodes.pending_xref, name: str) -> _SchematicEntry | def resolve_xref(self, env: BuildEnvironment, fromdocname: str, builder: Builder, typ: Literal['mapping', 'prop'], target: str, node: addnodes.pending_xref, contnode: Element): - ident = f'{typ}:{target}' ent: _SchematicEntry | None ent = self.find_obj(node, target) if ent is None: diff --git a/docs/crs/index.rst b/docs/crs/index.rst index d7a7d98f..3d7b67fe 100644 --- a/docs/crs/index.rst +++ b/docs/crs/index.rst @@ -51,7 +51,7 @@ Briefly, `CRS` concerns itself with the following high-level concepts: An acronym for :strong:`C`\ ompile-\ :strong:`R`\ eady :strong:`S`\ ource. CRS is a set of file formats and `JSON` schemas that describe a way to - destribute software in source-code format, ready to be given to any + distribute software in source-code format, ready to be given to any compatible compiler without further configuration or code generation. .. seealso:: :doc:`index` diff --git a/docs/design.rst b/docs/design.rst index 92878514..458c6f8f 100644 --- a/docs/design.rst +++ b/docs/design.rst @@ -183,7 +183,7 @@ No Arbitrary |#include| Directories =================================== Only ``src/`` and ``include/`` will ever be used as the basis for -`header resolution
` while building a project, so all +:term:`header resolution
` while building a project, so all |#include| directives should be relative to those directories. Refer to :ref:`libs.source-kinds`. @@ -199,5 +199,5 @@ every library in that dependency tree will be compiled with an identical set of options. Refer to the :doc:`guide/toolchains` page for more information. Currently, the only exception to this rules is for flags that control compiler -warnings: Dependencies will be compiled without adding any warnings flags, while -the main project will be compiled with warnings enabled by default. +diagnostics: Dependencies will be compiled without adding any warnings flags, +while the main project will be compiled with warnings enabled by default. diff --git a/docs/dev/reqs.rst b/docs/dev/reqs.rst index 7755d7e2..917710f9 100644 --- a/docs/dev/reqs.rst +++ b/docs/dev/reqs.rst @@ -13,10 +13,11 @@ Build Requirements Building |bpt| has a simple set of requirements: - **Python 3.7** or newer to run the bootstrap/CI scripts. -- A C++ compiler that has rudimentary support for several C++20 features, - including Concepts. Newer releases of Visual C++ that ship with **VS 2019** - will be sufficient on Windows, as will **GCC 10** with ``-std=c++20`` and - ``-fcoroutines`` on other platforms. +- A C++ compiler that has rudimentary support for several C++20 features. Newer + releases of Visual C++ that ship with **VS 2019** will be sufficient on + Windows, as will **GCC 10** with ``-std=c++20`` and ``-fcoroutines`` on other + platforms. **Note:** Using newer compiler versions may cause trouble as they + are untested, but adding support for these systems is planned. - On Linux, the OpenSSL headers are needed. This can be installed through the ``libssl-dev`` package on Debian/Ubuntu or ``openss-devel`` + ``openssl-static`` on RedHat systems. (For Windows, the |bpt| repository ships diff --git a/docs/dev/testing.rst b/docs/dev/testing.rst index c0b1d664..4891e7ab 100644 --- a/docs/dev/testing.rst +++ b/docs/dev/testing.rst @@ -13,7 +13,7 @@ within the :doc:`Poetry virtual environment `:: Note that individual tests can take between a few seconds and a few minutes to execute, so it may be useful to execute only a subset of the tests based on the functionality you want to test. Refer to -`the pytest documentation ` for more +`the pytest documentation `_ for more information about using and executing ``pytest``. If you are running the full test suite, you may also want to pass the ``-n`` argument with a number of parallel jobs to execute. diff --git a/docs/guide/build-deps.rst b/docs/guide/build-deps.rst index a63bd7ed..60e556ce 100644 --- a/docs/guide/build-deps.rst +++ b/docs/guide/build-deps.rst @@ -27,7 +27,7 @@ is not generated globally**: It is generated on a per-build basis as part of the build process. The manifest will describe in build-system-agnostic terms how to include and link against as set of libraries generated by a build. -|bpt| has first-class support for generating this index. The ``build-deps`` +|bpt| has first-class support for generating this file. The ``build-deps`` subcommand of |bpt| will download and build a set of dependencies, and places a `JSON` file that can be used to import the built results. @@ -50,9 +50,9 @@ Declaring Dependencies in a File `dependency specifiers ` as command line arguments, but it may be useful to specify those requirements in a file. -``bpt build-deps`` accepts a YAML file describing the dependencies of a project -as well. The only required property in the file is the ``dependencies`` key. -(The presence of any other key is an error.) +``bpt build-deps`` accepts a `YAML` file describing the dependencies of a +project as well. The only required property in the file is the ``dependencies`` +key. (The presence of any other key is an error.) Here is a simple dependencies file that declares a single requirement: diff --git a/docs/guide/cmake.rst b/docs/guide/cmake.rst index 331040e9..356a56e5 100644 --- a/docs/guide/cmake.rst +++ b/docs/guide/cmake.rst @@ -6,7 +6,7 @@ Using |bpt| in a CMake Project .. default-role:: term One of |bpt|'s primary goals is to inter-operate with other build systems -cleanly. Because of `CMakes ` ubiquity, |bpt| includes built-in support +cleanly. Because of `CMake's ` ubiquity, |bpt| includes built-in support for emitting files that can be imported into CMake. .. seealso:: @@ -51,11 +51,10 @@ Like with |bpt|, CMake wants us to explicitly declare how our build targets *use* other libraries. When we ``include()`` the generated CMake file, it will generate ``IMPORTED`` targets that can be linked against. -In |bpt| (and in libman), a library is identified by a combination of -*namespace* and *name*, joined together with a slash ``/`` character. This -*qualified name* of a library is decided by the original package author, and -should be documented. In the case of ``neo-sqlite3``, the only library is -``neo/sqlite3``. +In |bpt|, a library is identified by a combination of *namespace* and *name*, +joined together with a slash ``/`` character. This *qualified name* of a library +is decided by the original package author, and should be documented. In the case +of ``neo-sqlite3``, the only library is ``neo/sqlite3``. When the generated import file imports a library, it creates a qualified name using a double-colon "``::``" instead of a slash. As such, our ``neo/sqlite3`` diff --git a/docs/guide/deps.rst b/docs/guide/deps.rst index 4b439662..8518d387 100644 --- a/docs/guide/deps.rst +++ b/docs/guide/deps.rst @@ -193,6 +193,12 @@ Besides requiring that a candidate for dependency resolution meet the version requirements, the candidate must also provide all of the libraries named by the :cpp:`using` specifier on the dependency statement. +.. note:: + + If you omit the :cpp:`using` specifier, it is equivalent to :cpp:`using` a + library with the same name as the package. (This would be the + `default library` of the package.) + .. default-role:: math A Simple Example diff --git a/docs/guide/terms.rst b/docs/guide/terms.rst index d16ac745..bc2619ff 100644 --- a/docs/guide/terms.rst +++ b/docs/guide/terms.rst @@ -34,6 +34,10 @@ This page documents miscellaneous terminology used throughout |bpt| and `CRS`. JSON data cannot contain comments. The order of keys within a JSON object is not significant. + JSON5 + + A superset of `JSON` that permits comments, single-quote strings, multi-line + strings, trailing commas, and bare identifier keys. YAML diff --git a/docs/guide/toolchains.rst b/docs/guide/toolchains.rst index c737be13..ef2c6629 100644 --- a/docs/guide/toolchains.rst +++ b/docs/guide/toolchains.rst @@ -1,4 +1,4 @@ -.. highlight:: js +.. highlight:: yaml .. default-domain:: schematic .. default-role:: schematic:prop @@ -37,15 +37,14 @@ effectively in your project. Passing a Toolchain ******************* -In |bpt|, the default format of a toolchain is that of a single JSON5 file -that describes the entire toolchain. When running a build for a project, the -|bpt| executable will look in a few locations for a default toolchain, and +In |bpt|, the default format of a toolchain is that of a single :term:`YAML` +file that describes the entire toolchain. When running a build for a project, +the |bpt| executable will look in a few locations for a default toolchain, and generate an error if no default toolchain file is found (Refer to -:ref:`toolchains.default`). A different toolchain can be provided by passing -the toolchain file for the |--toolchain| (or ``-t``) option on the command -line:: +:ref:`toolchains.default`). A different toolchain can be provided by passing the +toolchain file for the |--toolchain| (or ``-t``) option on the command line:: - $ bpt build -t my-toolchain.json5 + $ bpt build -t my-toolchain.yaml Alternatively, you can pass the name of a built-in toolchain. See below. @@ -106,16 +105,16 @@ The following directories are searched, in order: #. ``$pwd/`` - If the working directory contains a toolchain file, it will be used as the default. -#. ``$bpt_config_dir/`` - Searches for a toolchain file in |bpt|'s user-local +#. ``/`` - Searches for a toolchain file in |bpt|'s user-local configuration directory (see below). -#. ``$user_home/`` - Searches for a toolchain file at the root of the current +#. ``/`` - Searches for a toolchain file at the root of the current user's home directory. (``$HOME`` on Unix-like systems, and ``$PROFILE`` on Windows.) -In each directory, it will search for ``toolchain.json5``, ``toolchain.jsonc``, -or ``toolchain.json``. +In each directory, it will search for ``toolchain.yaml``, ``toolchain.json5``, +``toolchain.jsonc``, or ``toolchain.json``. -The ``$bpt_config_dir`` directory is the |bpt| subdirectory of the user-local +The ```` directory is the |bpt| subdirectory of the user-local configuration directory. The user-local config directory is ``$XDG_CONFIG_DIR`` or ``~/.config`` on @@ -184,14 +183,21 @@ Flags for linking executables can be specified with } +.. note:: + + Command/flag list settings are subject to shell-like string splitting. String + splitting can be suppressed by using an array instead of a string. Refer: + :ref:`tc-splitting-note`. + .. _toolchains.opt-ref: Toolchain Option Reference ************************** +.. _tc-splitting-note: Understanding Flags and Shell Parsing -------------------------------------- +===================================== Many of the |bpt| toolchain parameters accept argument lists or shell-string lists. If such an option is given a single string, then that string is split @@ -217,6 +223,10 @@ Despite splitting strings as-if they were shell commands, |bpt| does nothing else shell-like. It does not expand environment variables, nor does it expand globs and wildcards. + +Toolchain Options Schema +======================== + .. mapping:: ToolchainOptions .. property:: compiler_id @@ -248,7 +258,7 @@ globs and wildcards. .. property:: cxx_compiler :optional: - :type: string + :type: :ts:`string` Names/paths of the C and C++ compilers, respectively. @@ -271,6 +281,8 @@ globs and wildcards. .. property:: cxx_version :optional: + :type: :ts:`string` + Specify the language versions for C and C++, respectively. By default, |bpt| will not set any language version. Using this option requires that the :prop:`~ToolchainOptions.compiler_id` be specified (Or the @@ -303,6 +315,7 @@ globs and wildcards. ``/std:c++latest``. **Beware** that this is an unstable setting value that could change the major language version in a future MSVC update. + .. property:: warning_flags :optional: @@ -323,7 +336,7 @@ globs and wildcards. .. seealso:: - Refer to :prop:`AdvancedToolchainOptions.base_warning_flags` for more + Refer to :prop:`~AdvancedToolchainOptions.base_warning_flags` for more information. @@ -378,13 +391,13 @@ globs and wildcards. Generates debug information embedded in the compiled binaries. - :option split: + :option "split": Generates debug information in a separate file from the compiled binaries. .. note:: - ``"split"`` with GCC requires that the compiler support the + ``"split"`` with GCC/Clang requires that the compiler support the ``-gsplit-dwarf`` option. :option true: Same as :ts:`"embedded"` @@ -427,7 +440,7 @@ globs and wildcards. .. note:: - On GNU-like compilers, setting :prop:`ToolchainOptions.runtime.static` to + On GNU-like compilers, setting :prop:`~ToolchainOptions.runtime.static` to |true| does not generate a static executable: it only statically links the runtime and standard library. To generate a static executable, the ``-static`` option should be added to ``link_flags``. @@ -571,10 +584,14 @@ Advanced Options Reference The placeholder for the output path for the executable file. + :placeholder [flags]: + + Placeholder for options specified using `~ToolchainOptions.link_flags`. + :default: |default-inferred-from-compiler_id|: - If |compiler_id| is |msvc|, then - `` /nologo /EHsc [in] /Fe[out]`` + `` /nologo /EHsc [in] /Fe[out] [flags]`` - If |compiler_id| is |gnu| or |clang|, then `` -fPIC [in] -pthread -o[out] [flags]`` - If |compiler_id| is unset, then this property must be specified. diff --git a/docs/howto/cmake.rst b/docs/howto/cmake.rst index 83b84dd5..7df97f2c 100644 --- a/docs/howto/cmake.rst +++ b/docs/howto/cmake.rst @@ -79,13 +79,13 @@ for now. The basic signature of the ``pmm(BPT)`` command looks like this:: pmm(BPT [DEP_FILES [filepaths...]] - [DEPENDS [dependencies...]] + [DEPENDENCIES [dependencies...]] [TOOLCHAIN file-or-id]) -The most straightforward usage is to use only the ``DEPENDS`` argument. For +The most straightforward usage is to use only the ``DEPENDENCIES`` argument. For example, if we want to import `{fmt} `_:: - pmm(BPT DEPENDS "fmt@7.0.3") + pmm(BPT DEPENDENCIES "fmt@7.0.3") When CMake executes the ``pmm(BPT ...)`` line above, PMM will download the appropriate |bpt| executable for your platform, generate @@ -140,7 +140,7 @@ In all, this is our final ``CMakeLists.txt``: project(MYApplication VERSION 2.1.3) include(tools/pmm.cmake) - pmm(BPT DEPENDS fmt@7.0.3) + pmm(BPT DEPENDENCIES fmt@7.0.3) add_executable(my-application app.cpp) target_link_libraries(my-application PRIVATE fmt::fmt) @@ -153,7 +153,7 @@ Changing Compile Options :doc:`toolchains `. PMM supports specifying a toolchain using the ``TOOLCHAIN`` argument:: - pmm(BPT DEPENDS fmt@7.0.3 TOOLCHAIN my-toolchain.json5) + pmm(BPT DEPENDENCIES fmt@7.0.3 TOOLCHAIN my-toolchain.json5) Of course, writing a separate toolchain file just for your dependencies can be tedious. For this reason, PMM will write a toolchain file on-the-fly when it