@@ -12,7 +12,7 @@ jobs: | |||
echo Executing Build and Tests | |||
reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f || exit 1 | |||
python -m pip install pytest pytest-xdist || exit 1 | |||
python -u tools/ci.py -B download -T tools\msvc.dds || exit 1 | |||
python -u tools/ci.py -B download -T tools\msvc.dds -T2 tools\msvc.jsonc || exit 1 | |||
displayName: Full CI | |||
- publish: _build/dds.exe | |||
artifact: DDS Executable - Windows VS2019 | |||
@@ -27,7 +27,7 @@ jobs: | |||
sudo apt install -y python3-minimal g++-9 ccache | |||
python3 -m pip install pytest pytest-xdist | |||
displayName: Prepare System | |||
- script: python3 -u tools/ci.py -B download -T tools/gcc-9.dds | |||
- script: python3 -u tools/ci.py -B download -T tools/gcc-9.dds -T2 tools/gcc-9.jsonc | |||
displayName: Full CI | |||
- publish: _build/dds | |||
artifact: DDS Executable - Linux | |||
@@ -41,7 +41,7 @@ jobs: | |||
- script: | | |||
set -eu | |||
python3 -m pip install pytest pytest-xdist | |||
python3 -u tools/ci.py -B download -T tools/gcc-9.dds | |||
python3 -u tools/ci.py -B download -T tools/gcc-9.dds -T2 tools/gcc-9.jsonc | |||
displayName: Build and Run Unit Tests | |||
- publish: _build/dds | |||
artifact: DDS Executable - macOS |
@@ -685,6 +685,31 @@ | |||
"url": "https://github.com/gabime/spdlog.git" | |||
} | |||
} | |||
}, | |||
"vob-json5": { | |||
"0.1.5": { | |||
"depends": {}, | |||
"description": "A C++ implementation of a JSON5 parser", | |||
"git": { | |||
"auto-lib": null, | |||
"ref": "0.1.5", | |||
"url": "https://github.com/vector-of-bool/json5.git" | |||
} | |||
} | |||
}, | |||
"vob-semester": { | |||
"0.1.0": { | |||
"depends": { | |||
"neo-concepts": "^0.2.1", | |||
"neo-fun": "^0.1.0" | |||
}, | |||
"description": "A C++ library to process recursive dynamic data", | |||
"git": { | |||
"auto-lib": null, | |||
"ref": "0.1.0", | |||
"url": "https://github.com/vector-of-bool/semester.git" | |||
} | |||
} | |||
} | |||
}, | |||
"version": 1 |
@@ -10,17 +10,17 @@ identifier would be ``ACME/Gadgets``. | |||
The "namespace" of a library in this case is arbitrary and not necessarily | |||
associated with any C++ ``namespace``. | |||
If more than one library declares itself to have the same ``Name`` and lives in | |||
the same ``Namespace``, ``dds`` will issue an error. | |||
If more than one library declares itself to have the same ``name`` and lives in | |||
the same ``namespace``, ``dds`` will issue an error. | |||
To avoid this error in your own project and to avoid causing this error in your | |||
downstream consumers, the ``Namespace`` of your package should be considered | |||
carefully and be unique. Do not use a ``Namespace`` that is likely to be used | |||
downstream consumers, the ``namespace`` of your package should be considered | |||
carefully and be unique. Do not use a ``namespace`` that is likely to be used | |||
by another developer or organization, especially generic names. | |||
If you are seeing this issue and it names a library that you do not own, it | |||
means that two or more of your dependencies are attempting to declare a library | |||
of the same ``Name`` in the same ``Namespace``. This issue should be raised | |||
of the same ``name`` in the same ``namespace``. This issue should be raised | |||
with the maintainers of the packages in question. | |||
.. seealso:: |
@@ -0,0 +1,11 @@ | |||
Error: Invalid library manifest | |||
############################### | |||
Every ``dds`` package must contain a valid library manifest for each library | |||
that it exports. These manifests are stored in the library root to which they | |||
correspond, and are stored in JSON5 format in ``library.json5`` (or similarly | |||
named file). | |||
The contents of this file must follow a prescribed content, or ``dds`` will | |||
reject the manifest. Refer to the :ref:`pkgs.libs` documentation page for more | |||
information about how to declare libraries. |
@@ -6,8 +6,8 @@ build and process packages and libraries. This structure isn't overly strict, | |||
and is thoroughly explained on the :doc:`/guide/packages` page. | |||
For exporting/generating a source distribution from a package, the *package | |||
root* requires a ``package.dds`` file and each *library root* requires a | |||
``library.dds`` file. | |||
root* requires a ``package.json5`` file and each *library root* requires a | |||
``library.json5`` file. | |||
.. . | |||
TODO: Create are more detailed reference page for package and library layout, |
@@ -0,0 +1,9 @@ | |||
Error: Invalid package manifest | |||
############################### | |||
Every ``dds`` 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 ``dds`` will | |||
reject the manifest. Refer to the :ref:`pkgs.pkgs` documentation page for more | |||
information about how to declare packages. |
@@ -3,7 +3,7 @@ Error: One or more tests failed | |||
This error message is printed when a project's tests encounter a failure | |||
condition. The exact behavior of tests is determined by a project's | |||
``Test-Driver``. | |||
``test_driver``. | |||
If you see this error, it is most likely that you have an issue in the tests of | |||
your project. |
@@ -1,8 +1,8 @@ | |||
Error: Unknown ``Test-Driver`` | |||
Error: Unknown ``test_driver`` | |||
############################## | |||
``dds`` has a set of known ``Test-Driver``s built-in, and they may be specified | |||
with the ``Test-Driver`` key. Receiving this error indicates that the specified | |||
``Test-Driver`` was not recognized by ``dds``. Check your spelling, and check | |||
``dds`` has a set of known ``test_driver``s built-in, and they may be specified | |||
with the ``test_driver`` key. Receiving this error indicates that the specified | |||
``test_driver`` was not recognized by ``dds``. Check your spelling, and check | |||
that the driver you want to use is supported by ``dds``. Refer to the | |||
:doc:`/guide/packages` page. |
@@ -2,11 +2,11 @@ Error: Unknown Usage/Linking Requirements | |||
######################################### | |||
A library can declare that it *uses* or *links* to another library by using the | |||
``Uses`` and ``Links`` keys in ``library.dds``, respectively. | |||
``uses`` and ``links`` keys in ``library.json5``, respectively. | |||
These requirements are specified by using the ``Namespace/Name`` pair that | |||
These requirements are specified by using the ``namespace/name`` pair that | |||
identifies a library. These are defined by both the project's dependencies and | |||
the project itself. If a ``Uses`` or ``Links`` key does not correspond to a | |||
the project itself. If a ``uses`` or ``links`` key does not correspond to a | |||
known library, ``dds`` will not be able to resolve the usage requirements, and | |||
will generate an error. | |||
@@ -33,7 +33,7 @@ command: | |||
dds catalog add <package-id> | |||
[--depends <requirement> [--depends <requirement> [...]]] | |||
[--git-url <url> --git-ref <ref>] | |||
[--auto-lib <Namespace>/<Name>] | |||
[--auto-lib <namespace>/<name>] | |||
The ``<package-id>`` positional arguments is the ``name@version`` package ID | |||
that will be added to the catalog. The following options are supported: | |||
@@ -41,14 +41,14 @@ that will be added to the catalog. The following options are supported: | |||
``--depends <requirement>`` | |||
This argument, which can be specified multiple times to represent multiple | |||
dependencies, sets the dependencies of the package within the catalog. If | |||
the obtained package root contains a ``package.dds``, then the dependencies | |||
listed here must be identical to those listed in ``package.dds``, or | |||
dependency resolution may yield unexpected results. | |||
the obtained package root contains a ``package.json5``, then the | |||
dependencies listed here must be identical to those listed in | |||
``package.json5``, or dependency resolution may yield unexpected results. | |||
``--git-url <url>`` | |||
Specify a Git URL to clone from to obtain the package. The root of the | |||
cloned repository must be a package root, but does not necessarily need to | |||
have the ``package.dds`` and ``library.dds`` files if relying on the | |||
have the ``package.json5`` and ``library.json5`` files if relying on the | |||
``--auto-lib`` parameter. | |||
``--git-ref`` **must** be passed with ``--git-url``. | |||
@@ -66,8 +66,8 @@ that will be added to the catalog. The following options are supported: | |||
can only be specified for packages that contain a single library root at | |||
the package root. | |||
The form of the argument is that of ``<Namespapce>/<Name>``, where | |||
``Namespace`` and ``Name`` are the usage requirement keys that should be | |||
The form of the argument is that of ``<namespace>/<name>``, where | |||
``namespace`` and ``name`` are the usage requirement keys that should be | |||
generated for the library. | |||
@@ -15,16 +15,18 @@ Package Dependencies | |||
******************** | |||
Consider that we are creating a package ``acme-gadgets@4.3.6``. We declare the | |||
name and version in the ``package.dds`` in the package root: | |||
name and version in the ``package.json5`` in the package root: | |||
.. code-block:: | |||
.. code-block:: js | |||
Name: acme-gadgets | |||
Version: 4.3.6 | |||
Namespace: acme | |||
{ | |||
name: 'acme-widgets', | |||
version: '4.3.6', | |||
namespace: 'acme', | |||
} | |||
.. note:: | |||
The ``Namespace`` field is required, but will be addressed in the | |||
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 | |||
@@ -32,14 +34,17 @@ Suppose that our package's libraries build upon the libraries in the | |||
not as new as ``2.0.0``. Such a dependency can be declared with the ``Depends`` | |||
key: | |||
.. code-block:: | |||
:emphasize-lines: 5 | |||
Name: acme-gadgets | |||
Version: 4.3.6 | |||
Namespace: acme | |||
.. code-block:: js | |||
:emphasize-lines: 5-7 | |||
Depends: acme-widgets ^1.4.3 | |||
{ | |||
name: 'acme-gadgets', | |||
version: '4.3.6', | |||
namespace: 'acme', | |||
depends: { | |||
'acme-widgets': '^1.4.3', | |||
}, | |||
} | |||
.. seealso:: :ref:`deps.ranges`. | |||
@@ -47,15 +52,18 @@ If we wish to declare additional dependencies, we simply declare them with | |||
additional ``Depends`` keys | |||
.. code-block:: | |||
:emphasize-lines: 5-7 | |||
Name: acme-gadgets | |||
Version: 4.3.6 | |||
Namespace: acme | |||
Depends: acme-widgets ^1.4.3 | |||
Depends: acme-gizmos ~5.6.5 | |||
Depends: acme-utils ^3.3.0 | |||
: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 ``dds`` attempts to build a project, it will first build the dependency | |||
solution by iteratively scanning the dependencies of the containing project and | |||
@@ -190,45 +198,50 @@ Library Dependencies | |||
In ``dds``, library interdependencies are tracked separately from the packages | |||
that contain them. A library must declare its intent to use another library | |||
in the ``library.dds`` at its library root. The minimal content of a | |||
``library.dds`` is the ``Name`` key: | |||
in the ``library.json5`` at its library root. The minimal content of a | |||
``library.json5`` is the ``name`` key: | |||
.. code-block:: | |||
.. code-block:: js | |||
Name: gadgets | |||
{ | |||
name: 'gadgets' | |||
} | |||
To announce that a library wishes to *use* another library, use the aptly-named | |||
``Uses`` key: | |||
.. code-block:: | |||
:emphasize-lines: 3-5 | |||
Name: gadgets | |||
Uses: acme/widgets | |||
Uses: acme/gizmos | |||
Uses: 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 ``/`` | |||
``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. | |||
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 | |||
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 | |||
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 ``<Namespace>/<Name>`` pair be | |||
However, it is essential that the ``<namespace>/<name>`` pair be | |||
universally unique, so choose wisely! | |||
Once the ``Uses`` key appears in the ``library.dds`` file of a library, ``dds`` | |||
Once the ``uses`` key appears in the ``library.dds`` file of a library, ``dds`` | |||
will make available the headers for the library being used, and will | |||
transitively propagate that usage requirement to users of the library. |
@@ -88,7 +88,7 @@ executable. | |||
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 | |||
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 ``dds`` | |||
when running unit tests. | |||
@@ -242,13 +242,14 @@ included in downstream binaries, but it will still generate link rules for the | |||
dependencies of a header-only library. | |||
In order for ``dds`` to be able to distribute and interlink libraries, a | |||
``library.dds`` file must be present at the corresponding library root. The | |||
only required key in a ``library.dds`` file is ``Name``: | |||
``library.json5`` file must be present at the corresponding library root. The | |||
only required key in a ``library.json5`` file is ``name``: | |||
.. code-block:: yaml | |||
Name: my-library | |||
.. code-block:: js | |||
{ | |||
name: 'my-library' | |||
} | |||
.. seealso:: More information is discussed on the :ref:`deps.lib-deps` page | |||
@@ -287,23 +288,25 @@ the ``name@version`` string forms the *package ID*, and it must be unique | |||
within a repository or package catalog. | |||
In order for a package to be exported by ``dds`` it must have a | |||
``package.dds`` file at its package root. Three keys are required to be | |||
present in the ``package.dds`` file: ``Name``, ``Version``, and ``Namespace``: | |||
``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:: yaml | |||
.. code-block:: js | |||
Name: acme-widgets | |||
Version: 6.7.3 | |||
Namespace: acme | |||
{ | |||
name: 'acme-widgets', | |||
version: '6.7.3', | |||
namespace: 'acme', | |||
} | |||
``Version`` must be a valid semantic version string. | |||
``version`` must be a valid semantic version string. | |||
.. note:: | |||
The ``Namespace`` key is arbitrary, and not necessarily associated with | |||
and C++ ``namespace``. | |||
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, | |||
The purpose of ``namespace``, as well as additional options in this file, | |||
are described in the :ref:`deps.pkg-deps` page | |||
@@ -315,8 +318,9 @@ 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 ASCII, lowercase characters, digits, | |||
underscores (``_``), hyphens (``-``), and periods (``.``). | |||
- 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 |
@@ -62,8 +62,8 @@ package ID as the name of the source distribution directory:: | |||
$ ls ./spdlog@1.4.2/ | |||
include/ | |||
src/ | |||
library.dds | |||
package.dds | |||
library.json5 | |||
package.json5 | |||
.. _repo.export-local: |
@@ -48,7 +48,7 @@ will already know the problem, but wouldn't it be better if we had better test | |||
diagnostics? | |||
A ``Test-Driver``: Using *Catch2* | |||
A ``test_driver``: Using *Catch2* | |||
********************************* | |||
``dds`` ships with built-in support for the `Catch2`_ C and C++ testing | |||
@@ -57,20 +57,21 @@ framework. | |||
.. _catch2: https://github.com/catchorg/Catch2 | |||
To make use of Catch as our test driver, we simply declare this intent in the | |||
``package.dds`` file at the package root: | |||
``package.json5`` file at the package root: | |||
.. code-block:: yaml | |||
:caption: ``<root>/package.dds`` | |||
.. code-block:: js | |||
:caption: ``<root>/package.json5`` | |||
:emphasize-lines: 5 | |||
Name: hello-dds | |||
Version: 0.1.0 | |||
Namespace: tutorial | |||
Test-Driver: Catch-Main | |||
{ | |||
name: 'hello-dds', | |||
version: '0.1.0', | |||
namespace: 'tutorial', | |||
test_driver: 'Catch-Main', | |||
} | |||
If you now run ``dds build``, we will get a linker error for a multiply-defined | |||
``main`` function. When setting the ``Test-Driver`` to ``Catch-Main``, ``dds`` | |||
``main`` function. When setting the ``test_driver`` to ``Catch-Main``, ``dds`` | |||
will compile an entrypoint separately from any particular test, and the tests | |||
will link against that entrypoint. This means we cannot provide our own | |||
``main`` function, and should instead use Catch's ``TEST_CASE`` macro to |
@@ -221,20 +221,21 @@ Creating a package manifest file. | |||
``dds`` 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 ``package.dds`` file to declare | |||
later tutorials, we'll need a simple ``package.json5`` file to declare | |||
information about are package. This file should be placed directly in the | |||
package root: | |||
.. code-block:: yaml | |||
:caption: ``<root>/package.dds`` | |||
Name: hello-dds | |||
Version: 0.1.0 | |||
Namespace: tutorial | |||
.. code-block:: js | |||
:caption: ``<root>/package.json5`` | |||
{ | |||
name: 'hello-dds', | |||
version: '0.1.0', | |||
namespace: 'tutorial', | |||
} | |||
.. note:: | |||
The ``Namespace`` option will be discussed later. | |||
The ``namespace`` option will be discussed later. | |||
Rebuilding the project will show no difference at the moment. | |||
@@ -7,4 +7,6 @@ Uses: nlohmann/json | |||
Uses: neo/sqlite3 | |||
Uses: neo/fun | |||
Uses: semver/semver | |||
Uses: vob/semester | |||
Uses: pubgrub/pubgrub | |||
Uses: vob/json5 |
@@ -0,0 +1,16 @@ | |||
{ | |||
"$schema": "./res/library-schema.json", | |||
"name": "dds", | |||
"uses": [ | |||
"spdlog/spdlog", | |||
"Microsoft/wil", | |||
"range-v3/range-v3", | |||
"nlohmann/json", | |||
"neo/sqlite3", | |||
"neo/fun", | |||
"semver/semver", | |||
"pubgrub/pubgrub", | |||
"vob/json5", | |||
"vob/semester", | |||
] | |||
} |
@@ -10,5 +10,7 @@ Depends: neo-sqlite3 0.2.2 | |||
Depends: neo-fun 0.1.0 | |||
Depends: semver 0.2.1 | |||
Depends: pubgrub 0.2.0 | |||
Depends: vob-json5 0.1.5 | |||
Depends: vob-semester 0.1.0 | |||
Test-Driver: Catch-Main | |||
Test-Driver: Catch-Main |
@@ -0,0 +1,19 @@ | |||
{ | |||
"$schema": "./res/package-schema.json", | |||
"name": "dds", | |||
"version": "0.1.0", | |||
"namespace": "dds", | |||
"depends": { | |||
"spdlog": "1.4.2", | |||
"ms-wil": "2019.11.10", | |||
"range-v3": "0.10.0", | |||
"nlohmann-json": "3.7.1", | |||
"neo-sqlite3": "0.2.2", | |||
"neo-fun": "0.1.0", | |||
"semver": "0.2.1", | |||
"pubgrub": "0.2.0", | |||
"vob-json5": "0.1.5", | |||
"vob-semester": "0.1.0" | |||
}, | |||
"test_driver": "Catch-Main" | |||
} |
@@ -0,0 +1,34 @@ | |||
{ | |||
"type": "object", | |||
"description": "DDS Library Manifest", | |||
"additionalProperties": false, | |||
"patternProperties": { | |||
"^\\$": {} | |||
}, | |||
"required": [ | |||
"name" | |||
], | |||
"properties": { | |||
"name": { | |||
"type": "string", | |||
"description": "The name of the library within the package.", | |||
"pattern": "^[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*$" | |||
}, | |||
"uses": { | |||
"type": "array", | |||
"items": { | |||
"type": "string", | |||
"description": "A library that is used by this library. Should be of the form `namespace/name`.", | |||
"pattern": "^[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*/[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*$" | |||
} | |||
}, | |||
"links": { | |||
"type": "array", | |||
"items": { | |||
"type": "string", | |||
"description": "A library that is linked to this library. Should be of the form `namespace/name`.", | |||
"pattern": "^[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*/[A-z][A-z0-9_]*((\\.|-)[A-z0-9_]+)*$" | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,53 @@ | |||
{ | |||
"type": "object", | |||
"description": "DDS Package Manifest", | |||
"additionalProperties": false, | |||
"patternProperties": { | |||
"^\\$": {} | |||
}, | |||
"required": [ | |||
"name", | |||
"version", | |||
"namespace" | |||
], | |||
"properties": { | |||
"name": { | |||
"type": "string", | |||
"description": "The name of the package", | |||
"pattern": "^[a-z][a-z0-9_]*((\\.|-)[a-z0-9_]+)*$" | |||
}, | |||
"version": { | |||
"type": "string", | |||
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$", | |||
"description": "The version of the package. Must be a valid Semantic Version string.", | |||
"default": "0.1.0" | |||
}, | |||
"namespace": { | |||
"type": "string", | |||
"description": "The package's namespace. Must be a valid string.", | |||
"pattern": "^[a-z][a-z0-9_]*((\\.|-)[a-z0-9_]+)*$" | |||
}, | |||
"$schema": { | |||
"type": "string", | |||
"description": "JSON schema tag. Ignored by dds." | |||
}, | |||
"depends": { | |||
"type": "object", | |||
"patternProperties": { | |||
"^[a-z][a-z0-9_]*((\\.|-)[a-z0-9_]+)*$": { | |||
"type": "string", | |||
"description": "The version of the dependency. Must be a valid Semantic Version string", | |||
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" | |||
} | |||
} | |||
}, | |||
"test_driver": { | |||
"type": "string", | |||
"default": "Catch-Main", | |||
"enum": [ | |||
"Catch-Main", | |||
"Catch" | |||
] | |||
} | |||
} | |||
} |
@@ -0,0 +1,183 @@ | |||
{ | |||
"type": "object", | |||
"description": "DDS Toolchain Description File", | |||
"additionalProperties": false, | |||
"patternProperties": { | |||
"^\\$": {} | |||
}, | |||
"definitions": { | |||
"command_line_flags": { | |||
"anyOf": [ | |||
{ | |||
"type": "string", | |||
"description": "Shell-style string of command-line arguments" | |||
}, | |||
{ | |||
"type": "array", | |||
"description": "An array of command-line arguments. Will be passed verbatim.", | |||
"items": { | |||
"type": "string", | |||
"description": "A single command-line argument. Will be passed verbatim." | |||
} | |||
} | |||
] | |||
} | |||
}, | |||
"properties": { | |||
"compiler_id": { | |||
"type": "string", | |||
"description": "The general compiler identification. This is one of a fixed set of values that DDS will use to infer most toolchain attributes.", | |||
"enum": [ | |||
"msvc", | |||
"gnu", | |||
"clang" | |||
] | |||
}, | |||
"c_compiler": { | |||
"type": "string", | |||
"description": "Executable name or filepath for a C compiler", | |||
"examples": [ | |||
"gcc", | |||
"clang-9", | |||
"cl.exe" | |||
] | |||
}, | |||
"cxx_compiler": { | |||
"type": "string", | |||
"description": "Executable name or filepath for a C++ compiler", | |||
"examples": [ | |||
"g++", | |||
"clang++-9", | |||
"cl.exe" | |||
] | |||
}, | |||
"flags": { | |||
"description": "Pass additional compile flags, regardless of the source language", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"c_flags": { | |||
"description": "Pass additional flags to the C compiler.", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"cxx_flags": { | |||
"description": "Pass additional flags to the C++ compiler.", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"c_version": { | |||
"description": "The C language version", | |||
"type": "string", | |||
"enum": [ | |||
"c89", | |||
"c99", | |||
"c11", | |||
"c18" | |||
] | |||
}, | |||
"cxx_version": { | |||
"description": "The C++ language version", | |||
"type": "string", | |||
"enum": [ | |||
"c++98", | |||
"c++03", | |||
"c++11", | |||
"c++14", | |||
"c++17", | |||
"c++20" | |||
] | |||
}, | |||
"warning_flags": { | |||
"description": "Set the flags that will be passed to the compiler to enable/disable warnings", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"link_flags": { | |||
"description": "Pass additional flags to the compiler when it is linking runtime binaries (executables)", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"compiler_launcher": { | |||
"description": "Set a command-line prefix that will be prepended to all compiler invocations", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"debug": { | |||
"description": "Enable the generation of debug information", | |||
"type": "boolean", | |||
"default": true | |||
}, | |||
"optimize": { | |||
"description": "Optimize generated code", | |||
"type": "boolean", | |||
"default": true | |||
}, | |||
"advanced": { | |||
"type": "object", | |||
"additionalProperties": false, | |||
"description": "Advanced toolchain options. All of these options will be inferred from `compiler_id` by default. Handle with care.", | |||
"properties": { | |||
"deps_mode": { | |||
"type": "string", | |||
"description": "Dependency tracking mode.", | |||
"enum": [ | |||
"msvc", | |||
"gnu", | |||
"none" | |||
] | |||
}, | |||
"include_template": { | |||
"description": "Set the include-directory flags template", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"external_include_template": { | |||
"description": "Set the external include-directory flags template", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"define_template": { | |||
"description": "Set the preprocessor-definition flags template", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"base_warning_flags": { | |||
"description": "Set the base warning flags for the toolchain. These are always prepended to `warning_flags`.", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"c_compile_file": { | |||
"description": "Set the command template for compiling C source files", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"cxx_compile_file": { | |||
"description": "Set the command template for compiling C++ source files", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"create_archive": { | |||
"description": "Set the command template for generating static library archives", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"link_executable": { | |||
"description": "Set the command template for linking executable binaries", | |||
"$ref": "#/definitions/command_line_flags" | |||
}, | |||
"obj_prefix": { | |||
"description": "Set the filename prefix for object files", | |||
"type": "string" | |||
}, | |||
"obj_suffix": { | |||
"description": "Set the filename suffix for object files", | |||
"type": "string" | |||
}, | |||
"archive_prefix": { | |||
"description": "Set the filename prefix for library archive files", | |||
"type": "string" | |||
}, | |||
"archive_suffix": { | |||
"description": "Set the filename suffix for library archive files", | |||
"type": "string" | |||
}, | |||
"exe_prefix": { | |||
"description": "Set the filename prefix for executable files", | |||
"type": "string" | |||
}, | |||
"exe_suffix": { | |||
"description": "Set the filename suffix for executable files", | |||
"type": "string" | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -5,7 +5,7 @@ | |||
#include <dds/error/errors.hpp> | |||
#include <dds/repo/repo.hpp> | |||
#include <dds/source/dist.hpp> | |||
#include <dds/toolchain/from_dds.hpp> | |||
#include <dds/toolchain/from_json.hpp> | |||
#include <dds/util/fs.hpp> | |||
#include <dds/util/paths.hpp> | |||
#include <dds/util/signal.hpp> | |||
@@ -58,7 +58,8 @@ struct toolchain_flag : string_flag { | |||
} | |||
return std::move(*tc); | |||
} else { | |||
return dds::parse_toolchain_dds(dds::slurp_file(tc_path)); | |||
return dds::parse_toolchain_json5(dds::slurp_file(tc_path)); | |||
// return dds::parse_toolchain_dds(dds::slurp_file(tc_path)); | |||
} | |||
} | |||
}; | |||
@@ -591,11 +592,9 @@ struct cli_build { | |||
params.out_root = out.Get(); | |||
params.toolchain = tc_filepath.get_toolchain(); | |||
params.parallel_jobs = n_jobs.Get(); | |||
dds::package_manifest man; | |||
const auto man_filepath = project.root.Get() / "package.dds"; | |||
if (exists(man_filepath)) { | |||
man = dds::package_manifest::load_from_file(man_filepath); | |||
} | |||
auto man = dds::package_manifest::load_from_directory(project.root.Get()) | |||
.value_or(dds::package_manifest{}); | |||
dds::builder bd; | |||
dds::sdist_build_params main_params; |
@@ -4,6 +4,7 @@ | |||
#include <dds/error/errors.hpp> | |||
#include <dds/proc.hpp> | |||
#include <nlohmann/json.hpp> | |||
#include <spdlog/spdlog.h> | |||
using namespace dds; | |||
@@ -32,12 +33,20 @@ temporary_sdist do_pull_sdist(const package_info& listing, const git_remote_list | |||
spdlog::info("Create sdist from clone ..."); | |||
if (git.auto_lib.has_value()) { | |||
spdlog::info("Generating library data automatically"); | |||
auto pkg_strm = dds::open(tmpdir.path() / "package.dds", std::ios::binary | std::ios::out); | |||
pkg_strm << "Name: " << listing.ident.name << '\n' // | |||
<< "Version: " << listing.ident.version.to_string() << '\n' // | |||
<< "Namespace: " << git.auto_lib->namespace_; | |||
auto lib_strm = dds::open(tmpdir.path() / "library.dds", std::ios::binary | std::ios::out); | |||
lib_strm << "Name: " << git.auto_lib->name; | |||
auto pkg_strm | |||
= dds::open(tmpdir.path() / "package.json5", std::ios::binary | std::ios::out); | |||
auto man_json = nlohmann::json::object(); | |||
man_json["name"] = listing.ident.name; | |||
man_json["version"] = listing.ident.version.to_string(); | |||
man_json["namespace"] = git.auto_lib->namespace_; | |||
pkg_strm << nlohmann::to_string(man_json); | |||
auto lib_strm | |||
= dds::open(tmpdir.path() / "library.json5", std::ios::binary | std::ios::out); | |||
auto lib_json = nlohmann::json::object(); | |||
lib_json["name"] = git.auto_lib->name; | |||
lib_strm << nlohmann::to_string(lib_json); | |||
} | |||
sdist_params params; |
@@ -41,6 +41,10 @@ std::string error_url_suffix(dds::errc ec) noexcept { | |||
return "sdist-ident-mismatch.html"; | |||
case errc::corrupted_build_db: | |||
return "corrupted-build-db.html"; | |||
case errc::invalid_lib_manifest: | |||
return "invalid-lib-manifest.html"; | |||
case errc::invalid_pkg_manifest: | |||
return "invalid-pkg-manifest.html"; | |||
case errc::invalid_version_range_string: | |||
return "invalid-version-string.html#range"; | |||
case errc::invalid_version_string: | |||
@@ -139,6 +143,16 @@ modified by a newer version of dds? | |||
The catalog database schema doesn't match what dds expects. This indicates that | |||
the database file has been modified in a way that dds cannot automatically fix | |||
and handle. | |||
)"; | |||
case errc::invalid_lib_manifest: | |||
return R"( | |||
A library manifest is malformed Refer to the documentation and above error | |||
message for more details. | |||
)"; | |||
case errc::invalid_pkg_manifest: | |||
return R"( | |||
The package manifest is malformed. Refer to the documentation and above error | |||
message for more details. | |||
)"; | |||
case errc::invalid_catalog_json: | |||
return R"( | |||
@@ -220,9 +234,9 @@ which packages are claiming the library name. | |||
)"; | |||
case errc::unknown_usage_name: | |||
return R"( | |||
A `Uses` or `Links` field for a library specifies a library of an unknown name. | |||
A `uses` or `links` field for a library specifies a library of an unknown name. | |||
Check your spelling, and check that the package containing the library is | |||
available, either from the `package.dds` or from the `INDEX.lmi` that was used | |||
available, either from the `package.json5` or from the `INDEX.lmi` that was used | |||
for the build. | |||
)"; | |||
case errc::none: | |||
@@ -266,35 +280,40 @@ std::string_view dds::default_error_string(dds::errc ec) noexcept { | |||
"that was expected of it"; | |||
case errc::corrupted_build_db: | |||
return "The build database file is corrupted"; | |||
case errc::invalid_lib_manifest: | |||
return "The library manifest is invalid"; | |||
case errc::invalid_pkg_manifest: | |||
return "The package manifest is invalid"; | |||
case errc::invalid_version_range_string: | |||
return "Attempted to parse an invalid version range string. <- (Seeing this text is a " | |||
"`dds` bug. Please report it.)"; | |||
case errc::invalid_version_string: | |||
return "Attempted to parse an invalid version string. <- (Seeing this text is a `dds` bug. " | |||
"Please report it.)"; | |||
return "Attempted to parse an invalid version string. <- (Seeing this text is a `dds` " | |||
"bug. Please report it.)"; | |||
case errc::invalid_config_key: | |||
return "Found an invalid configuration key. <- (Seeing this text is a `dds` bug. Please " | |||
"report it.)"; | |||
return "Found an invalid configuration key. <- (Seeing this text is a `dds` bug. " | |||
"Please report it.)"; | |||
case errc::invalid_lib_filesystem: | |||
case errc::invalid_pkg_filesystem: | |||
return "The filesystem structure of the package/library is invalid. <- (Seeing this text " | |||
"is a `dds` bug. Please report it.)"; | |||
return "The filesystem structure of the package/library is invalid. <- (Seeing this " | |||
"text is a `dds` bug. Please report it.)"; | |||
case errc::invalid_pkg_id: | |||
return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please " | |||
"report it.)"; | |||
case errc::invalid_pkg_name: | |||
return "A package name is invalid <- (Seeing this text is a `dds` bug. Please report it.)"; | |||
return "A package name is invalid <- (Seeing this text is a `dds` bug. Please report " | |||
"it.)"; | |||
case errc::sdist_exists: | |||
return "The source ditsribution already exists at the destination <- (Seeing this text is " | |||
"a `dds` bug. Please report it.)"; | |||
return "The source ditsribution already exists at the destination <- (Seeing this " | |||
"text is a `dds` bug. Please report it.)"; | |||
case errc::unknown_test_driver: | |||
return "The specified Test-Driver is not known to `dds`"; | |||
return "The specified test_driver is not known to `dds`"; | |||
case errc::dependency_resolve_failure: | |||
return "`dds` was unable to find a solution for the package dependencies given."; | |||
case errc::dup_lib_name: | |||
return "More than one library has claimed the same name."; | |||
case errc::unknown_usage_name: | |||
return "A `Uses` or `Links` field names a library that isn't recognized."; | |||
return "A `uses` or `links` field names a library that isn't recognized."; | |||
case errc::none: | |||
break; | |||
} |
@@ -29,6 +29,8 @@ enum class errc { | |||
corrupted_build_db, | |||
invalid_lib_manifest, | |||
invalid_pkg_manifest, | |||
invalid_version_range_string, | |||
invalid_version_string, | |||
invalid_pkg_id, |
@@ -1,16 +1,21 @@ | |||
#include "./manifest.hpp" | |||
#include <dds/dym.hpp> | |||
#include <dds/error/errors.hpp> | |||
#include <dds/util/algo.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
#include <libman/parse.hpp> | |||
#include <spdlog/fmt/fmt.h> | |||
#include <json5/parse_data.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
#include <semester/decomp.hpp> | |||
#include <spdlog/spdlog.h> | |||
using namespace dds; | |||
library_manifest library_manifest::load_from_file(const fs::path& fpath) { | |||
library_manifest library_manifest::load_from_dds_file(path_ref fpath) { | |||
spdlog::warn( | |||
"Using deprecated library.dds parsing (on file {}). This will be removed soon. Migrate!", | |||
fpath.string()); | |||
auto kvs = lm::parse_file(fpath); | |||
library_manifest ret; | |||
ret.name = fpath.parent_path().filename().string(); | |||
@@ -27,3 +32,107 @@ library_manifest library_manifest::load_from_file(const fs::path& fpath) { | |||
extend(ret.links, ranges::views::transform(links_strings, lm::split_usage_string)); | |||
return ret; | |||
} | |||
library_manifest library_manifest::load_from_file(path_ref fpath) { | |||
auto content = slurp_file(fpath); | |||
auto data = json5::parse_data(content); | |||
if (!data.is_object()) { | |||
throw_user_error<errc::invalid_lib_manifest>("Root value must be an object"); | |||
} | |||
library_manifest lib; | |||
using namespace semester::decompose_ops; | |||
auto res = semester::decompose( // | |||
data, | |||
try_seq{require_type<json5::data::mapping_type>{ | |||
"The root of the library manifest must be an object (mapping)"}, | |||
mapping{ | |||
if_key{"name", | |||
require_type<std::string>{"`name` must be a string"}, | |||
put_into{lib.name}}, | |||
if_key{"uses", | |||
require_type<json5::data::array_type>{ | |||
"`uses` must be an array of usage requirements"}, | |||
for_each{ | |||
require_type<std::string>{"`uses` elements must be strings"}, | |||
[&](auto&& uses) { | |||
lib.uses.push_back(lm::split_usage_string(uses.as_string())); | |||
return semester::dc_accept; | |||
}, | |||
}}, | |||
if_key{"links", | |||
require_type<json5::data::array_type>{ | |||
"`links` must be an array of usage requirements"}, | |||
for_each{ | |||
require_type<std::string>{"`links` elements must be strings"}, | |||
[&](auto&& links) { | |||
lib.links.push_back(lm::split_usage_string(links.as_string())); | |||
return semester::dc_accept; | |||
}, | |||
}}, | |||
}}); | |||
auto rej = std::get_if<semester::dc_reject_t>(&res); | |||
if (rej) { | |||
throw_user_error<errc::invalid_lib_manifest>(rej->message); | |||
} | |||
// using namespace json_read::ops; | |||
// json_read::decompose( // | |||
// data.as_object(), | |||
// object(key("name", require_string(put_into{lib.name}, "`name` must be a string")), | |||
// key("uses", | |||
// array_each{require_string( | |||
// [&](auto&& uses) { | |||
// lib.uses.push_back(lm::split_usage_string(uses.as_string())); | |||
// return json_read::accept_t{}; | |||
// }, | |||
// "All `uses` items must be strings")}), | |||
// key("links", | |||
// array_each{require_string( | |||
// [&](auto&& links) { | |||
// lib.links.push_back(lm::split_usage_string(links.as_string())); | |||
// return json_read::accept_t{}; | |||
// }, | |||
// "All `links` items must be strings")}))); | |||
if (lib.name.empty()) { | |||
throw_user_error<errc::invalid_lib_manifest>( | |||
"The 'name' field is required (Reading library manifest [{}])", fpath.string()); | |||
} | |||
return lib; | |||
} | |||
std::optional<fs::path> library_manifest::find_in_directory(path_ref dirpath) { | |||
auto fnames = { | |||
"library.json5", | |||
"library.jsonc", | |||
"library.json", | |||
}; | |||
for (auto c : fnames) { | |||
auto cand = dirpath / c; | |||
if (fs::is_regular_file(cand)) { | |||
return cand; | |||
} | |||
} | |||
auto dds_file = dirpath / "library.dds"; | |||
if (fs::is_regular_file(dds_file)) { | |||
return dds_file; | |||
} | |||
return std::nullopt; | |||
} | |||
std::optional<library_manifest> library_manifest::load_from_directory(path_ref dirpath) { | |||
auto found = find_in_directory(dirpath); | |||
if (!found.has_value()) { | |||
return std::nullopt; | |||
} | |||
if (found->extension() == ".dds") { | |||
return load_from_dds_file(*found); | |||
} else { | |||
return load_from_file(*found); | |||
} | |||
} |
@@ -9,9 +9,9 @@ | |||
namespace dds { | |||
/** | |||
* Represents the contents of a `library.dds`. This is somewhat a stripped-down | |||
* Represents the contents of a `library.json5`. This is somewhat a stripped-down | |||
* version of lm::library, to only represent exactly the parts that we want to | |||
* offer via `library.dds`. | |||
* offer via `library.json5`. | |||
*/ | |||
struct library_manifest { | |||
/// The name of the library | |||
@@ -24,7 +24,16 @@ struct library_manifest { | |||
/** | |||
* Load the library manifest from an existing file | |||
*/ | |||
static library_manifest load_from_file(const fs::path&); | |||
static library_manifest load_from_file(path_ref); | |||
static library_manifest load_from_dds_file(path_ref); | |||
/** | |||
* Find a library manifest within a directory. This will search for a few | |||
* file candidates and return the result from the first matching. If none | |||
* match, it will return nullopt. | |||
*/ | |||
static std::optional<fs::path> find_in_directory(path_ref); | |||
static std::optional<library_manifest> load_from_directory(path_ref); | |||
}; | |||
} // namespace dds |
@@ -55,10 +55,14 @@ library_root library_root::from_directory(path_ref lib_dir) { | |||
auto sources = collect_pf_sources(lib_dir); | |||
library_manifest man; | |||
man.name = lib_dir.filename().string(); | |||
auto man_path = lib_dir / "library.dds"; | |||
if (fs::is_regular_file(man_path)) { | |||
man = library_manifest::load_from_file(man_path); | |||
man.name = lib_dir.filename().string(); | |||
auto found = library_manifest::find_in_directory(lib_dir); | |||
if (found) { | |||
if (found->extension() == ".dds") { | |||
man = library_manifest::load_from_dds_file(*found); | |||
} else { | |||
man = library_manifest::load_from_file(*found); | |||
} | |||
} | |||
auto lib = library_root(lib_dir, std::move(sources), std::move(man)); |
@@ -8,11 +8,17 @@ | |||
#include <range/v3/view/split.hpp> | |||
#include <range/v3/view/split_when.hpp> | |||
#include <range/v3/view/transform.hpp> | |||
#include <spdlog/fmt/fmt.h> | |||
#include <semester/decomp.hpp> | |||
#include <spdlog/spdlog.h> | |||
#include <json5/parse_data.hpp> | |||
using namespace dds; | |||
package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
package_manifest package_manifest::load_from_dds_file(const fs::path& fpath) { | |||
spdlog::warn( | |||
"Using deprecated package.dds parsing (on file {}). This will be removed soon. Migrate!", | |||
fpath.string()); | |||
auto kvs = lm::parse_file(fpath); | |||
package_manifest ret; | |||
std::string version_str; | |||
@@ -45,7 +51,7 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
} else { | |||
auto dym = *did_you_mean(test_driver_str, {"Catch-Main", "Catch"}); | |||
throw_user_error< | |||
errc::unknown_test_driver>("Unknown 'Test-Driver' '{}' (Did you mean '{}'?)", | |||
errc::unknown_test_driver>("Unknown 'test_driver' '{}' (Did you mean '{}'?)", | |||
test_driver_str, | |||
dym); | |||
} | |||
@@ -63,3 +69,131 @@ package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
return ret; | |||
} | |||
package_manifest package_manifest::load_from_file(const fs::path& fpath) { | |||
auto content = slurp_file(fpath); | |||
auto data = json5::parse_data(content); | |||
if (!data.is_object()) { | |||
throw_user_error<errc::invalid_pkg_manifest>("Root value must be an object"); | |||
} | |||
package_manifest ret; | |||
using namespace semester::decompose_ops; | |||
auto res = semester::decompose( // | |||
data, | |||
try_seq{ | |||
require_type<json5::data::mapping_type>{ | |||
"The root of a package manifest must be an object (mapping)"}, | |||
mapping{ | |||
if_key{"$schema", just_accept}, | |||
if_key{ | |||
"name", | |||
require_type<std::string>{"`name` must be a string"}, | |||
put_into{ret.pkg_id.name}, | |||
}, | |||
if_key{ | |||
"namespace", | |||
require_type<std::string>{"`namespace` must be a string"}, | |||
put_into{ret.namespace_}, | |||
}, | |||
if_key{ | |||
"version", | |||
require_type<std::string>{"`version` must be a string"}, | |||
[&](auto&& version_str_) { | |||
auto& version = version_str_.as_string(); | |||
ret.pkg_id.version = semver::version::parse(version); | |||
return semester::dc_accept; | |||
}, | |||
}, | |||
if_key{ | |||
"depends", | |||
require_type<json5::data::mapping_type>{ | |||
"`depends` must be a mapping between package names and version ranges"}, | |||
mapping{[&](auto pkg_name, auto&& range_str_) { | |||
if (!range_str_.is_string()) { | |||
throw_user_error<errc::invalid_pkg_manifest>( | |||
"Dependency for '{}' must be a range string", pkg_name); | |||
} | |||
try { | |||
auto rng = semver::range::parse_restricted(range_str_.as_string()); | |||
dependency dep{std::string(pkg_name), {rng.low(), rng.high()}}; | |||
ret.dependencies.push_back(std::move(dep)); | |||
} catch (const semver::invalid_range&) { | |||
throw_user_error<errc::invalid_version_range_string>( | |||
"Invalid version range string '{}' in dependency declaration for " | |||
"'{}'", | |||
range_str_.as_string(), | |||
pkg_name); | |||
} | |||
return semester::dc_accept; | |||
}}, | |||
}, | |||
if_key{"test_driver", | |||
require_type<std::string>{"`test_driver` must be a string"}, | |||
[&](auto&& test_driver_str_) { | |||
auto& test_driver = test_driver_str_.as_string(); | |||
if (test_driver == "Catch-Main") { | |||
ret.test_driver = test_lib::catch_main; | |||
} else if (test_driver == "Catch") { | |||
ret.test_driver = test_lib::catch_; | |||
} else { | |||
auto dym = *did_you_mean(test_driver, {"Catch-Main", "Catch"}); | |||
throw_user_error<errc::unknown_test_driver>( | |||
"Unknown 'test_driver' '{}' (Did you mean '{}'?)", | |||
test_driver, | |||
dym); | |||
} | |||
return semester::dc_accept; | |||
}}, | |||
[&](auto key, auto&&) { | |||
return semester::dc_reject_t{ | |||
fmt::format("Unknown key `{}` in package manifest", key)}; | |||
}}}); | |||
auto rej = std::get_if<semester::dc_reject_t>(&res); | |||
if (rej) { | |||
throw_user_error<errc::invalid_pkg_manifest>(rej->message); | |||
} | |||
if (ret.pkg_id.name.empty()) { | |||
throw_user_error<errc::invalid_pkg_manifest>("The 'name' field is required."); | |||
} | |||
if (ret.namespace_.empty()) { | |||
throw_user_error<errc::invalid_pkg_manifest>("The 'namespace'` field is required."); | |||
} | |||
return ret; | |||
} | |||
std::optional<fs::path> package_manifest::find_in_directory(path_ref dirpath) { | |||
auto cands = { | |||
"package.json5", | |||
"package.jsonc", | |||
"package.json", | |||
}; | |||
for (auto c : cands) { | |||
auto cand = dirpath / c; | |||
if (fs::is_regular_file(cand)) { | |||
return cand; | |||
} | |||
} | |||
auto dds_fname = dirpath / "package.dds"; | |||
if (fs::is_regular_file(dds_fname)) { | |||
return dds_fname; | |||
} | |||
return std::nullopt; | |||
} | |||
std::optional<package_manifest> package_manifest::load_from_directory(path_ref dirpath) { | |||
auto found = find_in_directory(dirpath); | |||
if (!found.has_value()) { | |||
return std::nullopt; | |||
} | |||
if (found->extension() == ".dds") { | |||
return load_from_dds_file(*found); | |||
} else { | |||
return load_from_file(*found); | |||
} | |||
} |
@@ -11,7 +11,7 @@ | |||
namespace dds { | |||
/** | |||
* Possible values for Test-Driver in a package.dds | |||
* Possible values for test_driver in a package.json5 | |||
*/ | |||
enum class test_lib { | |||
catch_, | |||
@@ -26,7 +26,7 @@ struct package_manifest { | |||
package_id pkg_id; | |||
/// The declared `Namespace` of the package. This directly corresponds with the libman Namespace | |||
std::string namespace_; | |||
/// The `Test-Driver` that this package declares, or `nullopt` if absent. | |||
/// The `test_driver` that this package declares, or `nullopt` if absent. | |||
std::optional<test_lib> test_driver; | |||
/// The dependencies declared with the `Depends` fields, if any. | |||
std::vector<dependency> dependencies; | |||
@@ -35,6 +35,15 @@ struct package_manifest { | |||
* Load a package manifest from a file on disk. | |||
*/ | |||
static package_manifest load_from_file(path_ref); | |||
static package_manifest load_from_dds_file(path_ref); | |||
/** | |||
* Find a package manifest contained within a directory. This will search | |||
* for a few file candidates and return the result from the first matching. | |||
* If none match, it will return nullopt. | |||
*/ | |||
static std::optional<fs::path> find_in_directory(path_ref); | |||
static std::optional<package_manifest> load_from_directory(path_ref); | |||
}; | |||
} // namespace dds |
@@ -43,14 +43,14 @@ void sdist_copy_library(path_ref out_root, const library_root& lib, const sdist_ | |||
ranges::sort(sources_to_keep, std::less<>(), [](auto&& s) { return s.path; }); | |||
auto lib_dds_path = lib.path() / "library.dds"; | |||
if (!fs::is_regular_file(lib_dds_path)) { | |||
auto lib_man_path = library_manifest::find_in_directory(lib.path()); | |||
if (!lib_man_path) { | |||
throw_user_error<errc::invalid_lib_filesystem>( | |||
"Each library root in a source distribution requires a library manifest (Expected " | |||
"[{}])", | |||
lib_dds_path.string()); | |||
"Each library root in a source distribution requires a library manifest (Expected a " | |||
"library manifest in [{}])", | |||
lib.path().string()); | |||
} | |||
sdist_export_file(out_root, params.project_dir, lib_dds_path); | |||
sdist_export_file(out_root, params.project_dir, *lib_man_path); | |||
spdlog::info("sdist: Export library from {}", lib.path().string()); | |||
fs::create_directories(out_root); | |||
@@ -88,22 +88,24 @@ sdist dds::create_sdist_in_dir(path_ref out, const sdist_params& params) { | |||
sdist_copy_library(out, lib, params); | |||
} | |||
auto man_path = params.project_dir / "package.dds"; | |||
if (!fs::is_regular_file(man_path)) { | |||
auto man_path = package_manifest::find_in_directory(params.project_dir); | |||
if (!man_path) { | |||
throw_user_error<errc::invalid_pkg_filesystem>( | |||
"Creating a source distribution requires a package.dds file for the project (Expected " | |||
"[{}])", | |||
man_path.string()); | |||
"Creating a source distribution requires a package.json5 file for the project " | |||
"(Expected manifest in [{}])", | |||
params.project_dir.string()); | |||
} | |||
sdist_export_file(out, params.project_dir, man_path); | |||
auto pkg_man = package_manifest::load_from_file(man_path); | |||
auto pkg_man = man_path->extension() == ".dds" ? package_manifest::load_from_dds_file(*man_path) | |||
: package_manifest::load_from_file(*man_path); | |||
sdist_export_file(out, params.project_dir, *man_path); | |||
spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string()); | |||
return sdist::from_directory(out); | |||
} | |||
sdist sdist::from_directory(path_ref where) { | |||
auto pkg_man = package_manifest::load_from_file(where / "package.dds"); | |||
return sdist{std::move(pkg_man), where}; | |||
auto pkg_man = package_manifest::load_from_directory(where); | |||
// Code paths should only call here if they *know* that the sdist is valid | |||
assert(pkg_man.has_value()); | |||
return sdist{pkg_man.value(), where}; | |||
} |
@@ -1,18 +0,0 @@ | |||
#pragma once | |||
#include <dds/toolchain/toolchain.hpp> | |||
#include <libman/parse_fwd.hpp> | |||
#include <string_view> | |||
namespace dds { | |||
class toolchain; | |||
toolchain parse_toolchain_dds(std::string_view str, | |||
std::string_view context = "Loading toolchain file"); | |||
toolchain parse_toolchain_dds(const lm::pair_list&, | |||
std::string_view context = "Loading toolchain file"); | |||
} // namespace dds |
@@ -1,69 +1,28 @@ | |||
#include "./from_dds.hpp" | |||
#include "./from_json.hpp" | |||
#include <dds/dym.hpp> | |||
#include <dds/error/errors.hpp> | |||
#include <dds/toolchain/prep.hpp> | |||
#include <dds/toolchain/toolchain.hpp> | |||
#include <dds/util/algo.hpp> | |||
#include <dds/util/shlex.hpp> | |||
#include <libman/parse.hpp> | |||
#include <json5/parse_data.hpp> | |||
#include <semester/decomp.hpp> | |||
#include <spdlog/fmt/fmt.h> | |||
#include <map> | |||
#include <optional> | |||
#include <tuple> | |||
#include <vector> | |||
#include <string> | |||
using namespace dds; | |||
using fmt::format; | |||
using std::optional; | |||
using std::string; | |||
using std::vector; | |||
using string_seq = vector<string>; | |||
using opt_string = optional<string>; | |||
using opt_str_seq = optional<string_seq>; | |||
using strv = std::string_view; | |||
toolchain dds::parse_toolchain_dds(strv str, strv context) { | |||
auto kvs = lm::parse_string(str); | |||
return parse_toolchain_dds(kvs, context); | |||
} | |||
using string_seq = vector<string>; | |||
using opt_string = optional<string>; | |||
using opt_string_seq = optional<string_seq>; | |||
using strv = std::string_view; | |||
namespace { | |||
struct read_argv_acc { | |||
strv my_key; | |||
opt_str_seq& out; | |||
bool operator()(strv, strv key, strv value) const { | |||
if (key != my_key) { | |||
return false; | |||
} | |||
if (!out) { | |||
out.emplace(); | |||
} | |||
auto cmd = split_shell_string(value); | |||
extend(*out, cmd); | |||
return true; | |||
} | |||
}; | |||
struct read_argv { | |||
strv my_key; | |||
opt_str_seq& out; | |||
bool operator()(strv ctx, strv key, strv value) const { | |||
if (key != my_key) { | |||
return false; | |||
} | |||
if (out.has_value()) { | |||
throw std::runtime_error( | |||
format("{}: More than one value provided for key '{}'", ctx, key)); | |||
} | |||
out.emplace(split_shell_string(value)); | |||
return true; | |||
} | |||
}; | |||
template <typename T, typename Func> | |||
T read_opt(const std::optional<T>& what, Func&& fn) { | |||
@@ -75,109 +34,185 @@ T read_opt(const std::optional<T>& what, Func&& fn) { | |||
template <typename... Args> | |||
[[noreturn]] void fail(strv context, strv message, Args&&... args) { | |||
auto fmtd = format(message, args...); | |||
throw std::runtime_error(format("{} - Failed to read toolchain file: {}", context, fmtd)); | |||
auto fmtd = fmt::format(message, args...); | |||
throw std::runtime_error(fmt::format("{} - Failed to read toolchain file: {}", context, fmtd)); | |||
} | |||
} // namespace | |||
toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
toolchain dds::parse_toolchain_json5(std::string_view j5_str, std::string_view context) { | |||
auto dat = json5::parse_data(j5_str); | |||
return parse_toolchain_json_data(dat, context); | |||
} | |||
toolchain dds::parse_toolchain_json_data(const json5::data& dat, std::string_view context) { | |||
using namespace semester; | |||
opt_string compiler_id; | |||
opt_string c_compiler_fpath; | |||
opt_string cxx_compiler_fpath; | |||
opt_string c_compiler; | |||
opt_string cxx_compiler; | |||
opt_string c_version; | |||
opt_string cxx_version; | |||
opt_string_seq compiler_launcher; | |||
opt_string_seq common_flags; | |||
opt_string_seq c_flags; | |||
opt_string_seq cxx_flags; | |||
opt_string_seq link_flags; | |||
opt_string_seq warning_flags; | |||
optional<bool> do_debug; | |||
optional<bool> do_optimize; | |||
// Advanced-mode: | |||
opt_string deps_mode_str; | |||
opt_string archive_prefix; | |||
opt_string archive_suffix; | |||
opt_string obj_prefix; | |||
opt_string obj_suffix; | |||
opt_string exe_prefix; | |||
opt_string exe_suffix; | |||
opt_string deps_mode_str; | |||
optional<bool> do_debug; | |||
optional<bool> do_optimize; | |||
opt_str_seq include_template; | |||
opt_str_seq external_include_template; | |||
opt_str_seq define_template; | |||
opt_str_seq warning_flags; | |||
opt_str_seq flags; | |||
opt_str_seq c_flags; | |||
opt_str_seq cxx_flags; | |||
opt_str_seq link_flags; | |||
opt_str_seq c_compile_file; | |||
opt_str_seq cxx_compile_file; | |||
opt_str_seq create_archive; | |||
opt_str_seq link_executable; | |||
opt_str_seq compile_launcher; | |||
lm::read(context, | |||
pairs, | |||
// Base compile info: | |||
lm::read_opt("Compiler-ID", compiler_id), | |||
lm::read_opt("C-Compiler", c_compiler_fpath), | |||
lm::read_opt("C++-Compiler", cxx_compiler_fpath), | |||
// Language options | |||
lm::read_opt("C-Version", c_version), | |||
lm::read_opt("C++-Version", cxx_version), | |||
// Flag templates | |||
read_argv{"Include-Template", include_template}, | |||
read_argv{"External-Include-Template", include_template}, | |||
read_argv{"Define-Template", define_template}, | |||
// Flags | |||
read_argv_acc{"Warning-Flags", warning_flags}, | |||
read_argv_acc{"Flags", flags}, | |||
read_argv_acc{"C-Flags", c_flags}, | |||
read_argv_acc{"C++-Flags", cxx_flags}, | |||
read_argv_acc{"Link-Flags", link_flags}, | |||
// Options for flags | |||
lm::read_bool("Optimize", do_optimize), | |||
lm::read_bool("Debug", do_debug), | |||
// Miscellaneous | |||
read_argv{"Compiler-Launcher", compile_launcher}, | |||
lm::read_opt("Deps-Mode", deps_mode_str), | |||
// Command templates | |||
read_argv{"C-Compile-File", c_compile_file}, | |||
read_argv{"C++-Compile-File", cxx_compile_file}, | |||
read_argv{"Create-Archive", create_archive}, | |||
read_argv{"Link-Executable", link_executable}, | |||
// Filename affixes | |||
lm::read_opt("Archive-Prefix", archive_prefix), | |||
lm::read_opt("Archive-Suffix", archive_suffix), | |||
lm::read_opt("Object-Prefix", obj_prefix), | |||
lm::read_opt("Object-Suffix", obj_suffix), | |||
lm::read_opt("Executable-Prefix", exe_prefix), | |||
lm::read_opt("Executable-Suffix", exe_suffix), | |||
// Die: | |||
lm_reject_dym{{ | |||
"Compiler-ID", | |||
"C-Compiler", | |||
"C++-Compiler", | |||
"C-Version", | |||
"C++-Version", | |||
"Include-Template", | |||
"External-Include-Template", | |||
"Define-Template", | |||
"Warning-Flags", | |||
"Flags", | |||
"C-Flags", | |||
"C++-Flags", | |||
"Link-Flags", | |||
"Optimize", | |||
"Debug", | |||
"Compiler-Launcher", | |||
"Deps-Mode", | |||
"C-Compile-File", | |||
"C++-Compile-File", | |||
"Create-Archive", | |||
"Link-Executable", | |||
"Archive-Prefix", | |||
"Archive-Suffix", | |||
"Object-Prefix", | |||
"Object-Suffix", | |||
"Executable-Prefix", | |||
"Executable-Suffix", | |||
}}); | |||
opt_string_seq base_warning_flags; | |||
opt_string_seq include_template; | |||
opt_string_seq external_include_template; | |||
opt_string_seq define_template; | |||
opt_string_seq c_compile_file; | |||
opt_string_seq cxx_compile_file; | |||
opt_string_seq create_archive; | |||
opt_string_seq link_executable; | |||
// For copy-pasting convenience: ‘{}’ | |||
auto extend_flags = [&](string key, auto& opt_flags) { | |||
return [&opt_flags, key](const json5::data& dat) { | |||
if (!opt_flags) { | |||
opt_flags.emplace(); | |||
} | |||
return decompose( // | |||
dat, | |||
try_seq{ | |||
if_type<string>([&](auto& str_) { | |||
auto more_flags = split_shell_string(str_.as_string()); | |||
extend(*opt_flags, more_flags); | |||
return dc_accept; | |||
}), | |||
if_array{for_each{ | |||
require_type<string>{ | |||
fmt::format("Elements of `{}` array must be strings", key)}, | |||
write_to{std::back_inserter(*opt_flags)}, | |||
}}, | |||
reject_with{fmt::format("`{}` must be an array or a shell-like string", key)}, | |||
}); | |||
}; | |||
}; | |||
toolchain_prep tc; | |||
#define KEY_EXTEND_FLAGS(Name) \ | |||
if_key { #Name, extend_flags(#Name, Name) } | |||
#define KEY_STRING(Name) \ | |||
if_key { #Name, require_type < string>("`" #Name "` must be a string"), put_into{Name }, } | |||
auto result = semester::decompose( // | |||
dat, | |||
try_seq{ | |||
require_type<json5::data::mapping_type>("Root of toolchain data must be a mapping"), | |||
mapping{ | |||
if_key{"$schema", just_accept}, | |||
KEY_STRING(compiler_id), | |||
KEY_STRING(c_compiler), | |||
KEY_STRING(cxx_compiler), | |||
KEY_STRING(c_version), | |||
KEY_STRING(cxx_version), | |||
KEY_EXTEND_FLAGS(c_flags), | |||
KEY_EXTEND_FLAGS(cxx_flags), | |||
KEY_EXTEND_FLAGS(warning_flags), | |||
KEY_EXTEND_FLAGS(link_flags), | |||
KEY_EXTEND_FLAGS(compiler_launcher), | |||
if_key{"debug", | |||
require_type<bool>("`debug` must be a boolean value"), | |||
put_into{do_debug}}, | |||
if_key{"optimize", | |||
require_type<bool>("`optimize` must be a boolean value"), | |||
put_into{do_optimize}}, | |||
if_key{"flags", extend_flags("flags", common_flags)}, | |||
if_key{ | |||
"advanced", | |||
require_type<json5::data::mapping_type>("`advanced` must be a mapping"), | |||
mapping{ | |||
if_key{"deps_mode", | |||
require_type<string>("`deps_mode` must be a string"), | |||
put_into{deps_mode_str}}, | |||
KEY_EXTEND_FLAGS(include_template), | |||
KEY_EXTEND_FLAGS(external_include_template), | |||
KEY_EXTEND_FLAGS(define_template), | |||
KEY_EXTEND_FLAGS(base_warning_flags), | |||
KEY_EXTEND_FLAGS(c_compile_file), | |||
KEY_EXTEND_FLAGS(cxx_compile_file), | |||
KEY_EXTEND_FLAGS(create_archive), | |||
KEY_EXTEND_FLAGS(link_executable), | |||
KEY_STRING(obj_prefix), | |||
KEY_STRING(obj_suffix), | |||
KEY_STRING(archive_prefix), | |||
KEY_STRING(archive_suffix), | |||
KEY_STRING(exe_prefix), | |||
KEY_STRING(exe_suffix), | |||
[&](auto key, auto) -> dc_reject_t { | |||
auto dym = did_you_mean(key, | |||
{ | |||
"deps_mode", | |||
"include_template", | |||
"external_include_template", | |||
"define_template", | |||
"base_warning_flags", | |||
"c_compile_file", | |||
"cxx_compile_file", | |||
"create_archive", | |||
"link_executable", | |||
"obj_prefix", | |||
"obj_suffix", | |||
"archive_prefix", | |||
"archive_suffix", | |||
"exe_prefix", | |||
"exe_suffix", | |||
}); | |||
fail(context, | |||
"Unknown toolchain advanced-config key ‘{}’ (Did you mean ‘{}’?)", | |||
key, | |||
*dym); | |||
std::terminate(); | |||
}, | |||
}, | |||
}, | |||
[&](auto key, auto &&) -> dc_reject_t { | |||
// 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", | |||
}); | |||
fail(context, | |||
"Unknown toolchain config key ‘{}’ (Did you mean ‘{}’?)", | |||
key, | |||
*dym); | |||
std::terminate(); | |||
}, | |||
}, | |||
}); | |||
auto rej_opt = std::get_if<dc_reject_t>(&result); | |||
if (rej_opt) { | |||
fail(context, rej_opt->message); | |||
} | |||
enum compiler_id_e_t { | |||
no_comp_id, | |||
@@ -188,14 +223,14 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
= [&] { | |||
if (!compiler_id) { | |||
return no_comp_id; | |||
} else if (compiler_id == "MSVC") { | |||
} else if (compiler_id == "msvc") { | |||
return msvc; | |||
} else if (compiler_id == "GNU") { | |||
} else if (compiler_id == "gnu") { | |||
return gnu; | |||
} else if (compiler_id == "Clang") { | |||
} else if (compiler_id == "clang") { | |||
return clang; | |||
} else { | |||
fail(context, "Unknown Compiler-ID '{}'", *compiler_id); | |||
fail(context, "Invalid `compiler_id` value ‘{}’", *compiler_id); | |||
} | |||
}(); | |||
@@ -213,27 +248,32 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
} else { | |||
return file_deps_mode::none; | |||
} | |||
} else if (deps_mode_str == "GNU") { | |||
} else if (deps_mode_str == "gnu") { | |||
return file_deps_mode::gnu; | |||
} else if (deps_mode_str == "MSVC") { | |||
} else if (deps_mode_str == "msvc") { | |||
return file_deps_mode::msvc; | |||
} else if (deps_mode_str == "None") { | |||
} else if (deps_mode_str == "none") { | |||
return file_deps_mode::none; | |||
} else { | |||
fail(context, "Unknown Deps-Mode '{}'", *deps_mode_str); | |||
fail(context, "Invalid `deps_mode` value ‘{}’", *deps_mode_str); | |||
} | |||
}(); | |||
// Now convert the flags we've been given into a real toolchain | |||
auto get_compiler = [&](language lang) -> string { | |||
if (lang == language::cxx && cxx_compiler_fpath) { | |||
return *cxx_compiler_fpath; | |||
auto get_compiler_executable_path = [&](language lang) -> string { | |||
if (lang == language::cxx && cxx_compiler) { | |||
return *cxx_compiler; | |||
} | |||
if (lang == language::c && c_compiler_fpath) { | |||
return *c_compiler_fpath; | |||
if (lang == language::c && c_compiler) { | |||
return *c_compiler; | |||
} | |||
if (!compiler_id.has_value()) { | |||
fail(context, "Unable to determine what compiler to use."); | |||
if (lang == language::c) { | |||
fail(context, "Unable to determine the executable for a C compiler"); | |||
} | |||
if (lang == language::cxx) { | |||
fail(context, "Unable to determine the executable for a C++ compiler"); | |||
} | |||
} | |||
if (is_gnu) { | |||
return (lang == language::cxx) ? "g++" : "gcc"; | |||
@@ -248,6 +288,7 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
std::terminate(); | |||
}; | |||
// Determine the C language version | |||
enum c_version_e_t { | |||
c_none, | |||
c89, | |||
@@ -258,16 +299,16 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
= [&] { | |||
if (!c_version) { | |||
return c_none; | |||
} else if (c_version == "C89") { | |||
} else if (c_version == "c89") { | |||
return c89; | |||
} else if (c_version == "C99") { | |||
} else if (c_version == "c99") { | |||
return c99; | |||
} else if (c_version == "C11") { | |||
} else if (c_version == "c11") { | |||
return c11; | |||
} else if (c_version == "C18") { | |||
} else if (c_version == "c18") { | |||
return c18; | |||
} else { | |||
fail(context, "Unknown C-Version '{}'", *c_version); | |||
fail(context, "Unknown `c_version` ‘{}’", *c_version); | |||
} | |||
}(); | |||
@@ -283,20 +324,20 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
= [&] { | |||
if (!cxx_version) { | |||
return cxx_none; | |||
} else if (cxx_version == "C++98") { | |||
} else if (cxx_version == "c++98") { | |||
return cxx98; | |||
} else if (cxx_version == "C++03") { | |||
} else if (cxx_version == "c++03") { | |||
return cxx03; | |||
} else if (cxx_version == "C++11") { | |||
} else if (cxx_version == "c++11") { | |||
return cxx11; | |||
} else if (cxx_version == "C++14") { | |||
} else if (cxx_version == "c++14") { | |||
return cxx14; | |||
} else if (cxx_version == "C++17") { | |||
} else if (cxx_version == "c++17") { | |||
return cxx17; | |||
} else if (cxx_version == "C++20") { | |||
} else if (cxx_version == "c++20") { | |||
return cxx20; | |||
} else { | |||
fail(context, "Unknown C++-Version '{}'", *cxx_version); | |||
fail(context, "Unknown `cxx_version` ‘{}’", *cxx_version); | |||
} | |||
}(); | |||
@@ -320,7 +361,7 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
auto get_c_version_flags = [&]() -> string_seq { | |||
if (!compiler_id.has_value()) { | |||
fail(context, "Unable to deduce flags for 'C-Version' without setting 'Compiler-ID'"); | |||
fail(context, "Unable to deduce flags for 'c_version' without setting 'compiler_id'"); | |||
} | |||
auto c_ver_iter = c_version_flag_table.find({compiler_id_e, c_version_e}); | |||
assert(c_ver_iter != c_version_flag_table.end()); | |||
@@ -353,7 +394,7 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
auto get_cxx_version_flags = [&]() -> string_seq { | |||
if (!compiler_id.has_value()) { | |||
fail(context, "Unable to deduce flags for 'C++-Version' without setting 'Compiler-ID'"); | |||
fail(context, "Unable to deduce flags for 'cxx_version' without setting 'compiler_id'"); | |||
} | |||
auto cxx_ver_iter = cxx_version_flag_table.find({compiler_id_e, cxx_version_e}); | |||
assert(cxx_ver_iter != cxx_version_flag_table.end()); | |||
@@ -388,18 +429,6 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
auto get_flags = [&](language lang) -> string_seq { | |||
string_seq ret; | |||
if (lang == language::cxx && cxx_flags) { | |||
extend(ret, *cxx_flags); | |||
} | |||
if (lang == language::cxx && cxx_version) { | |||
extend(ret, get_cxx_version_flags()); | |||
} | |||
if (lang == language::c && c_flags) { | |||
extend(ret, *c_flags); | |||
} | |||
if (lang == language::c && c_version) { | |||
extend(ret, get_c_version_flags()); | |||
} | |||
if (is_msvc) { | |||
strv rt_lib = "/MT"; | |||
if (do_optimize.has_value() && *do_optimize) { | |||
@@ -430,44 +459,56 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
"<IN>", | |||
"-o<OUT>"}); | |||
} | |||
if (flags) { | |||
extend(ret, *flags); | |||
if (common_flags) { | |||
extend(ret, *common_flags); | |||
} | |||
if (lang == language::cxx && cxx_flags) { | |||
extend(ret, *cxx_flags); | |||
} | |||
if (lang == language::cxx && cxx_version) { | |||
extend(ret, get_cxx_version_flags()); | |||
} | |||
if (lang == language::c && c_flags) { | |||
extend(ret, *c_flags); | |||
} | |||
if (lang == language::c && c_version) { | |||
extend(ret, get_c_version_flags()); | |||
} | |||
return ret; | |||
}; | |||
toolchain_prep tc; | |||
tc.deps_mode = deps_mode; | |||
tc.c_compile = read_opt(c_compile_file, [&] { | |||
string_seq c; | |||
if (compile_launcher) { | |||
extend(c, *compile_launcher); | |||
if (compiler_launcher) { | |||
extend(c, *compiler_launcher); | |||
} | |||
c.push_back(get_compiler(language::c)); | |||
c.push_back(get_compiler_executable_path(language::c)); | |||
extend(c, get_flags(language::c)); | |||
return c; | |||
}); | |||
tc.cxx_compile = read_opt(cxx_compile_file, [&] { | |||
string_seq cxx; | |||
if (compile_launcher) { | |||
extend(cxx, *compile_launcher); | |||
if (compiler_launcher) { | |||
extend(cxx, *compiler_launcher); | |||
} | |||
cxx.push_back(get_compiler(language::cxx)); | |||
cxx.push_back(get_compiler_executable_path(language::cxx)); | |||
extend(cxx, get_flags(language::cxx)); | |||
return cxx; | |||
}); | |||
tc.include_template = read_opt(include_template, [&]() -> string_seq { | |||
if (!compiler_id) { | |||
fail(context, "Cannot deduce 'Include-Template' without 'Compiler-ID'"); | |||
fail(context, "Cannot deduce 'include_template' without 'compiler_id'"); | |||
} | |||
if (is_gnu_like) { | |||
return {"-I", "<PATH>"}; | |||
} else if (is_msvc) { | |||
return {"/I", "<PATH>"}; | |||
} | |||
assert(false && "Include-Template deduction failed"); | |||
assert(false && "'include_template' deduction failed"); | |||
std::terminate(); | |||
}); | |||
@@ -482,20 +523,20 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
// MSVC has external-header support inbound, but it is not fully ready yet | |||
return {"/I", "<PATH>"}; | |||
} | |||
assert(false && "External-Include-Template deduction failed"); | |||
assert(false && "external_include_template deduction failed"); | |||
std::terminate(); | |||
}); | |||
tc.define_template = read_opt(define_template, [&]() -> string_seq { | |||
if (!compiler_id) { | |||
fail(context, "Cannot deduce 'Define-Template' without 'Compiler-ID'"); | |||
fail(context, "Cannot deduce 'define_template' without 'compiler_id'"); | |||
} | |||
if (is_gnu_like) { | |||
return {"-D", "<DEF>"}; | |||
} else if (is_msvc) { | |||
return {"/D", "<DEF>"}; | |||
} | |||
assert(false && "Define-Template deduction failed"); | |||
assert(false && "define_template deduction failed"); | |||
std::terminate(); | |||
}); | |||
@@ -536,6 +577,7 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
#endif | |||
}); | |||
/// TODO: Handle base_warning_flags: | |||
tc.warning_flags = read_opt(warning_flags, [&]() -> string_seq { | |||
if (!compiler_id) { | |||
// No error. Just no warning flags | |||
@@ -552,7 +594,7 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
tc.link_archive = read_opt(create_archive, [&]() -> string_seq { | |||
if (!compiler_id) { | |||
fail(context, "Unable to deduce archive creation rules without a Compiler-ID"); | |||
fail(context, "Unable to deduce archive creation rules without a 'compiler_id'"); | |||
} | |||
if (is_msvc) { | |||
return {"lib", "/nologo", "/OUT:<OUT>", "<IN>"}; | |||
@@ -565,13 +607,17 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
tc.link_exe = read_opt(link_executable, [&]() -> string_seq { | |||
if (!compiler_id) { | |||
fail(context, "Unable to deduce how to link executables without a Compiler-ID"); | |||
fail(context, "Unable to deduce how to link executables without a 'compiler_id'"); | |||
} | |||
string_seq ret; | |||
if (is_msvc) { | |||
ret = {get_compiler(language::cxx), "/nologo", "/EHsc", "<IN>", "/Fe<OUT>"}; | |||
ret = {get_compiler_executable_path(language::cxx), | |||
"/nologo", | |||
"/EHsc", | |||
"<IN>", | |||
"/Fe<OUT>"}; | |||
} else if (is_gnu_like) { | |||
ret = {get_compiler(language::cxx), | |||
ret = {get_compiler_executable_path(language::cxx), | |||
"-fPIC", | |||
"-fdiagnostics-color", | |||
"<IN>", | |||
@@ -586,4 +632,4 @@ toolchain dds::parse_toolchain_dds(const lm::pair_list& pairs, strv context) { | |||
}); | |||
return tc.realize(); | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
#pragma once | |||
#include <dds/toolchain/toolchain.hpp> | |||
#include <json5/data.hpp> | |||
#include <string_view> | |||
namespace dds { | |||
toolchain parse_toolchain_json5(std::string_view json5, | |||
std::string_view context = "Loading toolchain JSON"); | |||
toolchain parse_toolchain_json_data(const json5::data& data, | |||
std::string_view context = "Loading toolchain JSON"); | |||
} // namespace dds |
@@ -1,18 +1,16 @@ | |||
#include <dds/toolchain/from_dds.hpp> | |||
#include <dds/toolchain/from_json.hpp> | |||
#include <dds/proc.hpp> | |||
// #include <dds/util.test.hpp> | |||
#include <catch2/catch.hpp> | |||
namespace { | |||
void check_tc_compile(std::string_view tc_content, | |||
std::string_view expected_compile, | |||
std::string_view expected_compile_warnings, | |||
std::string_view expected_ar, | |||
std::string_view expected_exe) { | |||
auto tc = dds::parse_toolchain_dds(tc_content); | |||
auto tc = dds::parse_toolchain_json5(tc_content); | |||
dds::compile_file_spec cf; | |||
cf.source_path = "foo.cpp"; | |||
@@ -43,9 +41,11 @@ void check_tc_compile(std::string_view tc_content, | |||
CHECK(exe_cmd_str == expected_exe); | |||
} | |||
} // namespace | |||
TEST_CASE("Generating toolchain commands") { | |||
check_tc_compile( | |||
"Compiler-ID: GNU", | |||
"{compiler_id: 'gnu'}", | |||
"g++ -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o", | |||
"g++ -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " | |||
"-MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o", | |||
@@ -53,7 +53,7 @@ TEST_CASE("Generating toolchain commands") { | |||
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe"); | |||
check_tc_compile( | |||
"Compiler-ID: GNU\nDebug: True", | |||
"{compiler_id: 'gnu', debug: true}", | |||
"g++ -g -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o", | |||
"g++ -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " | |||
"-MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o", | |||
@@ -61,7 +61,7 @@ TEST_CASE("Generating toolchain commands") { | |||
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe -g"); | |||
check_tc_compile( | |||
"Compiler-ID: GNU\nDebug: True\nOptimize: True", | |||
"{compiler_id: 'gnu', debug: true, optimize: true}", | |||
"g++ -O2 -g -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -MT foo.o -c foo.cpp " | |||
"-ofoo.o", | |||
"g++ -O2 -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " | |||
@@ -69,22 +69,30 @@ TEST_CASE("Generating toolchain commands") { | |||
"ar rcs stuff.a foo.o bar.o", | |||
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe -O2 -g"); | |||
check_tc_compile("Compiler-ID: MSVC", | |||
check_tc_compile("{compiler_id: 'msvc'}", | |||
"cl.exe /MT /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o", | |||
"cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o", | |||
"lib /nologo /OUT:stuff.a foo.o bar.o", | |||
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT"); | |||
check_tc_compile( | |||
"Compiler-ID: MSVC\nDebug: True", | |||
"{compiler_id: 'msvc', debug: true}", | |||
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o", | |||
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o", | |||
"lib /nologo /OUT:stuff.a foo.o bar.o", | |||
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /Z7 /DEBUG /MTd"); | |||
auto tc = dds::parse_toolchain_dds(R"( | |||
Compiler-ID: GNU | |||
)"); | |||
check_tc_compile( | |||
"{compiler_id: 'msvc', flags: '-DFOO'}", | |||
"cl.exe /MT /EHsc /nologo /permissive- /showIncludes /c foo.cpp /Fofoo.o -DFOO", | |||
"cl.exe /MT /EHsc /nologo /permissive- /W4 /showIncludes /c foo.cpp /Fofoo.o -DFOO", | |||
"lib /nologo /OUT:stuff.a foo.o bar.o", | |||
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT"); | |||
} | |||
TEST_CASE("Manipulate a toolchain and file compilation") { | |||
auto tc = dds::parse_toolchain_json5("{compiler_id: 'gnu'}"); | |||
dds::compile_file_spec cfs; | |||
cfs.source_path = "foo.cpp"; | |||
@@ -141,6 +149,4 @@ TEST_CASE("Generating toolchain commands") { | |||
"-c", | |||
"foo.cpp", | |||
"-ofoo.o"}); | |||
} | |||
} // namespace | |||
} |
@@ -1,6 +1,6 @@ | |||
#include "./toolchain.hpp" | |||
#include <dds/toolchain/from_dds.hpp> | |||
#include <dds/toolchain/from_json.hpp> | |||
#include <dds/toolchain/prep.hpp> | |||
#include <dds/util/algo.hpp> | |||
#include <dds/util/paths.hpp> | |||
@@ -148,31 +148,32 @@ vector<string> toolchain::create_link_executable_command(const link_exe_spec& sp | |||
std::optional<toolchain> toolchain::get_builtin(std::string_view tc_id) noexcept { | |||
using namespace std::literals; | |||
std::string tc_content; | |||
json5::data tc_data = json5::data::mapping_type(); | |||
auto& root_map = tc_data.as_object(); | |||
if (starts_with(tc_id, "debug:")) { | |||
tc_id = tc_id.substr("debug:"sv.length()); | |||
tc_content += "Debug: True\n"; | |||
root_map.emplace("debug", true); | |||
} | |||
if (starts_with(tc_id, "ccache:")) { | |||
tc_id = tc_id.substr("ccache:"sv.length()); | |||
tc_content += "Compiler-Launcher: ccache\n"; | |||
root_map.emplace("compiler_launcher", "ccache"); | |||
} | |||
#define CXX_VER_TAG(str, version) \ | |||
if (starts_with(tc_id, str)) { \ | |||
tc_id = tc_id.substr(std::string_view(str).length()); \ | |||
tc_content += "C++-Version: "s + version + "\n"; \ | |||
root_map.emplace("cxx_version", version); \ | |||
} \ | |||
static_assert(true) | |||
CXX_VER_TAG("c++98:", "C++98"); | |||
CXX_VER_TAG("c++03:", "C++03"); | |||
CXX_VER_TAG("c++11:", "C++11"); | |||
CXX_VER_TAG("c++14:", "C++14"); | |||
CXX_VER_TAG("c++17:", "C++17"); | |||
CXX_VER_TAG("c++20:", "C++20"); | |||
CXX_VER_TAG("c++98:", "c++98"); | |||
CXX_VER_TAG("c++03:", "c++03"); | |||
CXX_VER_TAG("c++11:", "c++11"); | |||
CXX_VER_TAG("c++14:", "c++14"); | |||
CXX_VER_TAG("c++17:", "c++17"); | |||
CXX_VER_TAG("c++20:", "c++20"); | |||
struct compiler_info { | |||
string c; | |||
@@ -187,9 +188,9 @@ std::optional<toolchain> toolchain::get_builtin(std::string_view tc_id) noexcept | |||
const auto [c_compiler_base, cxx_compiler_base, compiler_id] = [&]() -> compiler_info { | |||
if (is_gcc) { | |||
return {"gcc", "g++", "GNU"}; | |||
return {"gcc", "g++", "gnu"}; | |||
} else if (is_clang) { | |||
return {"clang", "clang++", "Clang"}; | |||
return {"clang", "clang++", "clang"}; | |||
} | |||
assert(false && "Unreachable"); | |||
std::terminate(); | |||
@@ -221,7 +222,7 @@ std::optional<toolchain> toolchain::get_builtin(std::string_view tc_id) noexcept | |||
auto cxx_compiler_name = cxx_compiler_base + compiler_suffix; | |||
return compiler_info{c_compiler_name, cxx_compiler_name, compiler_id}; | |||
} else if (tc_id == "msvc") { | |||
return compiler_info{"cl.exe", "cl.exe", "MSVC"}; | |||
return compiler_info{"cl.exe", "cl.exe", "msvc"}; | |||
} else { | |||
return std::nullopt; | |||
} | |||
@@ -231,22 +232,28 @@ std::optional<toolchain> toolchain::get_builtin(std::string_view tc_id) noexcept | |||
return std::nullopt; | |||
} | |||
tc_content += "C-Compiler: "s + opt_triple->c + "\n"; | |||
tc_content += "C++-Compiler: "s + opt_triple->cxx + "\n"; | |||
tc_content += "Compiler-ID: " + opt_triple->id + "\n"; | |||
return parse_toolchain_dds(tc_content); | |||
root_map.emplace("c_compiler", opt_triple->c); | |||
root_map.emplace("cxx_compiler", opt_triple->cxx); | |||
root_map.emplace("compiler_id", opt_triple->id); | |||
return parse_toolchain_json_data(tc_data); | |||
} | |||
std::optional<dds::toolchain> dds::toolchain::get_default() { | |||
auto candidates = { | |||
fs::current_path() / "toolchain.dds", | |||
dds_config_dir() / "toolchain.dds", | |||
user_home_dir() / "toolchain.dds", | |||
fs::current_path() / "toolchain.json5", | |||
fs::current_path() / "toolchain.jsonc", | |||
fs::current_path() / "toolchain.json", | |||
dds_config_dir() / "toolchain.json5", | |||
dds_config_dir() / "toolchain.jsonc", | |||
dds_config_dir() / "toolchain.json", | |||
user_home_dir() / "toolchain.json5", | |||
user_home_dir() / "toolchain.jsonc", | |||
user_home_dir() / "toolchain.json", | |||
}; | |||
for (auto&& cand : candidates) { | |||
if (fs::exists(cand)) { | |||
return parse_toolchain_dds(slurp_file(cand)); | |||
return parse_toolchain_json5(slurp_file(cand)); | |||
} | |||
} | |||
return std::nullopt; | |||
} | |||
} |
@@ -17,9 +17,12 @@ def test_build_simple(dds: DDS): | |||
def basic_pkg_dds(dds: DDS): | |||
return set_contents( | |||
dds.source_root / 'package.dds', b''' | |||
Name: test-pkg | |||
Version: 0.2.2 | |||
dds.source_root / 'package.json5', b''' | |||
{ | |||
name: 'test-pkg', | |||
version: '0.2.2', | |||
namespace: 'test', | |||
} | |||
''') | |||
@@ -3,6 +3,8 @@ import json | |||
from tests import dds, DDS | |||
from tests.fileutil import ensure_dir | |||
import pytest | |||
def test_get(dds: DDS): | |||
dds.scope.enter_context(ensure_dir(dds.build_dir)) | |||
@@ -16,8 +18,10 @@ def test_get(dds: DDS): | |||
'0.2.2': { | |||
'depends': {}, | |||
'git': { | |||
'url': 'https://github.com/vector-of-bool/neo-sqlite3.git', | |||
'ref': '0.2.2', | |||
'url': | |||
'https://github.com/vector-of-bool/neo-sqlite3.git', | |||
'ref': | |||
'0.2.2', | |||
}, | |||
}, | |||
}, |
@@ -5,7 +5,7 @@ | |||
"0.1.0": { | |||
"git": { | |||
"url": "https://github.com/vector-of-bool/neo-buffer.git", | |||
"ref": "develop" | |||
"ref": "0.1.0" | |||
}, | |||
"depends": {} | |||
} |
@@ -1,5 +0,0 @@ | |||
Name: deps-test | |||
Version: 0.0.0 | |||
Depends: neo-buffer 0.1.0 | |||
Depends: range-v3 0.9.1 |
@@ -0,0 +1,9 @@ | |||
{ | |||
name: 'deps-test', | |||
"namespace": "test", | |||
version: '0.0.0', | |||
depends: { | |||
'neo-buffer': '0.1.0', | |||
'range-v3': '0.9.1', | |||
} | |||
} |
@@ -1,2 +0,0 @@ | |||
Name: deps-test | |||
Version: 0.0.0 |
@@ -0,0 +1,5 @@ | |||
{ | |||
name: 'deps-test', | |||
version: '0.0.0', | |||
"namespace": "test", | |||
} |
@@ -1,3 +0,0 @@ | |||
Name: dummy | |||
Uses: nlohmann/json |
@@ -0,0 +1,6 @@ | |||
{ | |||
name: "dummy", | |||
uses: [ | |||
'nlohmann/json', | |||
] | |||
} |
@@ -1,4 +0,0 @@ | |||
Name: json-test | |||
Version: 0.0.0 | |||
Depends: nlohmann-json 3.7.1 |
@@ -0,0 +1,8 @@ | |||
{ | |||
"name": "json-test", | |||
"version": "0.0.0", | |||
"namespace": "test", | |||
"depends": { | |||
"nlohmann-json": "3.7.1" | |||
} | |||
} |
@@ -0,0 +1,6 @@ | |||
{ | |||
"compiler_id": 'gnu', | |||
"cxx_version": 'c++17', | |||
"cxx_compiler": 'g++-9', | |||
"flags": '-DSPDLOG_COMPILED_LIB', | |||
} |
@@ -0,0 +1,4 @@ | |||
{ | |||
"compiler_id": 'msvc', | |||
"flags": '-DSPDLOG_COMPILED_LIB', | |||
} |
@@ -1,3 +0,0 @@ | |||
Name: spdlog-user | |||
Uses: spdlog/spdlog |
@@ -0,0 +1,6 @@ | |||
{ | |||
name: 'spdlog-user', | |||
uses: [ | |||
'spdlog/spdlog', | |||
] | |||
} |
@@ -1,4 +0,0 @@ | |||
Name: test | |||
Version: 0.0.0 | |||
Depends: spdlog 1.4.2 |
@@ -0,0 +1,8 @@ | |||
{ | |||
name: 'test', | |||
version: '0.0.0', | |||
"namespace": "test", | |||
depends: { | |||
'spdlog': '1.4.2', | |||
}, | |||
} |
@@ -5,7 +5,7 @@ from dds_ci import proc | |||
def test_get_build_use_spdlog(dds: DDS): | |||
dds.catalog_import(dds.source_root / 'catalog.json') | |||
tc_fname = 'gcc.tc.dds' if 'gcc' in dds.default_builtin_toolchain else 'msvc.tc.dds' | |||
tc_fname = 'gcc.tc.jsonc' if 'gcc' in dds.default_builtin_toolchain else 'msvc.tc.jsonc' | |||
tc = str(dds.test_dir / tc_fname) | |||
dds.build(toolchain=tc, apps=True) | |||
proc.check_run((dds.build_dir / 'use-spdlog').with_suffix(dds.exe_suffix)) |
@@ -1 +0,0 @@ | |||
Name: foo |
@@ -0,0 +1,3 @@ | |||
{ | |||
"name": "foo" | |||
} |
@@ -1,2 +0,0 @@ | |||
Name: foo | |||
Version: 1.2.3 |
@@ -0,0 +1,5 @@ | |||
{ | |||
name: 'foo', | |||
version: '1.2.3', | |||
"namespace": "test", | |||
} |
@@ -1,4 +0,0 @@ | |||
Name: Test | |||
Version: 0.0.0 | |||
Test-Driver: Catch |
@@ -0,0 +1,6 @@ | |||
{ | |||
"name": "test", | |||
"version": "0.0.0", | |||
"namespace": "test", | |||
"test_driver": "Catch", | |||
} |
@@ -1,4 +0,0 @@ | |||
Name: Test | |||
Version: 0.0.0 | |||
Test-Driver: Catch-Main |
@@ -0,0 +1,6 @@ | |||
{ | |||
"name": "test", | |||
"version": "0.0.0", | |||
"namespace": "test", | |||
"test_driver": "Catch-Main", | |||
} |
@@ -14,6 +14,7 @@ from dds_ci import paths, proc | |||
class CIOptions(NamedTuple): | |||
toolchain: str | |||
toolchain_json5: str | |||
def _do_bootstrap_build(opts: CIOptions) -> None: | |||
@@ -67,9 +68,16 @@ def main(argv: Sequence[str]) -> int: | |||
'-T', | |||
help='The toolchain to use for the CI process', | |||
required=True) | |||
parser.add_argument( | |||
'--toolchain-json5', | |||
'-T2', | |||
help='The toolchain JSON to use with the bootstrapped executable', | |||
required=True, | |||
) | |||
args = parser.parse_args(argv) | |||
opts = CIOptions(toolchain=args.toolchain) | |||
opts = CIOptions( | |||
toolchain=args.toolchain, toolchain_json5=args.toolchain_json5) | |||
if args.bootstrap_with == 'build': | |||
_do_bootstrap_build(opts) | |||
@@ -117,7 +125,7 @@ def main(argv: Sequence[str]) -> int: | |||
]) | |||
self_build( | |||
paths.CUR_BUILT_DDS, | |||
toolchain=opts.toolchain, | |||
toolchain=opts.toolchain_json5, | |||
dds_flags=[f'--repo-dir={ci_repo_dir}', f'--catalog={cat_path}']) | |||
print('Bootstrap test PASSED!') | |||
@@ -5,7 +5,7 @@ C++-Compiler: g++-9 | |||
# Range-v3 0.10.0 contains an accidental conversion warning | |||
Flags: -D SPDLOG_COMPILED_LIB -Werror=return-type -Wno-conversion | |||
C++-Flags: -fconcepts | |||
Link-Flags: -static-libgcc -static-libstdc++ | |||
# Debug: True | |||
Optimize: True | |||
# Link-Flags: -static-libgcc -static-libstdc++ | |||
Debug: True | |||
#Optimize: True | |||
Compiler-Launcher: ccache |
@@ -0,0 +1,17 @@ | |||
{ | |||
"$schema": "../res/toolchain-schema.json", | |||
"compiler_id": "gnu", | |||
"c_compiler": "gcc-9", | |||
"cxx_compiler": "g++-9", | |||
"cxx_version": "c++17", | |||
"flags": [ | |||
"-DSPDLOG_COMPILED_LIB", // Required to use a compiled spdlog | |||
"-Werror=return-type" | |||
], | |||
"cxx_flags": [ | |||
"-fconcepts" | |||
], | |||
// "debug": true, | |||
"optimize": true, | |||
"compiler_launcher": "ccache" | |||
} |
@@ -30,7 +30,7 @@ class Version(NamedTuple): | |||
ret: dict = { | |||
'description': self.description, | |||
} | |||
ret['depends'] = {} | |||
ret['depends'] = self.depends | |||
if isinstance(self.remote, Git): | |||
ret['git'] = self.remote.to_dict() | |||
return ret | |||
@@ -150,6 +150,23 @@ packages = [ | |||
'A C++ implementation of the Pubgrub version solving algorithm', | |||
git_url='https://github.com/vector-of-bool/pubgrub.git', | |||
), | |||
many_versions( | |||
'vob-json5', | |||
('0.1.5', ), | |||
description='A C++ implementation of a JSON5 parser', | |||
git_url='https://github.com/vector-of-bool/json5.git', | |||
), | |||
Package('vob-semester', [ | |||
Version( | |||
'0.1.0', | |||
description='A C++ library to process recursive dynamic data', | |||
remote=Git('https://github.com/vector-of-bool/semester.git', | |||
'0.1.0'), | |||
depends={ | |||
'neo-fun': '^0.1.0', | |||
'neo-concepts': '^0.2.1', | |||
}), | |||
]), | |||
many_versions( | |||
'spdlog', | |||
( |
@@ -0,0 +1,14 @@ | |||
{ | |||
"$schema": "../res/toolchain-schema.json", | |||
"compiler_id": "msvc", | |||
"flags": [ | |||
"/experimental:preprocessor", // Required for range-v3 | |||
"/DSPDLOG_COMPILED_LIB", // Required to use spdlog as a compiled lib | |||
"/std:c++latest", | |||
], | |||
"link_flags": [ | |||
"rpcrt4.lib", | |||
], | |||
// "debug": true, | |||
"optimize": true | |||
} |