Browse Source

Merge branch 'feature/use-json5' into develop

default_compile_flags
vector-of-bool 4 years ago
parent
commit
b3aac5c06f
68 changed files with 1299 additions and 469 deletions
  1. +3
    -3
      azure-pipelines.yml
  2. +25
    -0
      catalog.json
  3. +5
    -5
      docs/err/dup-lib-name.rst
  4. +11
    -0
      docs/err/invalid-lib-manifest.rst
  5. +2
    -2
      docs/err/invalid-pkg-filesystem.rst
  6. +9
    -0
      docs/err/invalid-pkg-manifest.rst
  7. +1
    -1
      docs/err/test-failure.rst
  8. +4
    -4
      docs/err/unknown-test-driver.rst
  9. +3
    -3
      docs/err/unknown-usage.rst
  10. +7
    -7
      docs/guide/catalog.rst
  11. +60
    -47
      docs/guide/interdeps.rst
  12. +22
    -18
      docs/guide/packages.rst
  13. +2
    -2
      docs/guide/repo.rst
  14. +11
    -10
      docs/tut/hello-test.rst
  15. +9
    -8
      docs/tut/hello-world.rst
  16. +2
    -0
      library.dds
  17. +16
    -0
      library.jsonc
  18. +3
    -1
      package.dds
  19. +19
    -0
      package.jsonc
  20. +34
    -0
      res/library-schema.json
  21. +53
    -0
      res/package-schema.json
  22. +183
    -0
      res/toolchain-schema.json
  23. +6
    -7
      src/dds.main.cpp
  24. +15
    -6
      src/dds/catalog/get.cpp
  25. +32
    -13
      src/dds/error/errors.cpp
  26. +2
    -0
      src/dds/error/errors.hpp
  27. +113
    -4
      src/dds/library/manifest.cpp
  28. +12
    -3
      src/dds/library/manifest.hpp
  29. +8
    -4
      src/dds/library/root.cpp
  30. +137
    -3
      src/dds/package/manifest.cpp
  31. +11
    -2
      src/dds/package/manifest.hpp
  32. +18
    -16
      src/dds/source/dist.cpp
  33. +0
    -18
      src/dds/toolchain/from_dds.hpp
  34. +245
    -199
      src/dds/toolchain/from_json.cpp
  35. +17
    -0
      src/dds/toolchain/from_json.hpp
  36. +21
    -15
      src/dds/toolchain/from_json.test.cpp
  37. +30
    -23
      src/dds/toolchain/toolchain.cpp
  38. +6
    -3
      tests/basics/test_basics.py
  39. +6
    -2
      tests/catalog/get_test.py
  40. +1
    -1
      tests/deps/git-remote/catalog.json
  41. +0
    -5
      tests/deps/git-remote/package.dds
  42. +9
    -0
      tests/deps/git-remote/package.json5
  43. +0
    -2
      tests/deps/no-deps/package.dds
  44. +5
    -0
      tests/deps/no-deps/package.json5
  45. +0
    -3
      tests/deps/use-remote/library.dds
  46. +6
    -0
      tests/deps/use-remote/library.json5
  47. +0
    -4
      tests/deps/use-remote/package.dds
  48. +8
    -0
      tests/deps/use-remote/package.json5
  49. +6
    -0
      tests/deps/use-spdlog/gcc.tc.jsonc
  50. +4
    -0
      tests/deps/use-spdlog/msvc.tc.jsonc
  51. +0
    -3
      tests/deps/use-spdlog/project/library.dds
  52. +6
    -0
      tests/deps/use-spdlog/project/library.json5
  53. +0
    -4
      tests/deps/use-spdlog/project/package.dds
  54. +8
    -0
      tests/deps/use-spdlog/project/package.json5
  55. +1
    -1
      tests/deps/use-spdlog/use_spdlog_test.py
  56. +0
    -1
      tests/sdist/create/library.dds
  57. +3
    -0
      tests/sdist/create/library.jsonc
  58. +0
    -2
      tests/sdist/create/package.dds
  59. +5
    -0
      tests/sdist/create/package.json5
  60. +0
    -4
      tests/test_drivers/catch/custom-runner/package.dds
  61. +6
    -0
      tests/test_drivers/catch/custom-runner/package.json5
  62. +0
    -4
      tests/test_drivers/catch/main/package.dds
  63. +6
    -0
      tests/test_drivers/catch/main/package.json5
  64. +10
    -2
      tools/ci.py
  65. +3
    -3
      tools/gcc-9.dds
  66. +17
    -0
      tools/gcc-9.jsonc
  67. +18
    -1
      tools/gen-catalog-json.py
  68. +14
    -0
      tools/msvc.jsonc

+ 3
- 3
azure-pipelines.yml View File

echo Executing Build and Tests echo Executing Build and Tests
reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f || exit 1 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 -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 displayName: Full CI
- publish: _build/dds.exe - publish: _build/dds.exe
artifact: DDS Executable - Windows VS2019 artifact: DDS Executable - Windows VS2019
sudo apt install -y python3-minimal g++-9 ccache sudo apt install -y python3-minimal g++-9 ccache
python3 -m pip install pytest pytest-xdist python3 -m pip install pytest pytest-xdist
displayName: Prepare System 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 displayName: Full CI
- publish: _build/dds - publish: _build/dds
artifact: DDS Executable - Linux artifact: DDS Executable - Linux
- script: | - script: |
set -eu set -eu
python3 -m pip install pytest pytest-xdist 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 displayName: Build and Run Unit Tests
- publish: _build/dds - publish: _build/dds
artifact: DDS Executable - macOS artifact: DDS Executable - macOS

+ 25
- 0
catalog.json View File

"url": "https://github.com/gabime/spdlog.git" "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 "version": 1

+ 5
- 5
docs/err/dup-lib-name.rst View File

The "namespace" of a library in this case is arbitrary and not necessarily The "namespace" of a library in this case is arbitrary and not necessarily
associated with any C++ ``namespace``. 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 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. 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 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 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. with the maintainers of the packages in question.


.. seealso:: .. seealso::

+ 11
- 0
docs/err/invalid-lib-manifest.rst View File

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.

+ 2
- 2
docs/err/invalid-pkg-filesystem.rst View File

and is thoroughly explained on the :doc:`/guide/packages` page. and is thoroughly explained on the :doc:`/guide/packages` page.


For exporting/generating a source distribution from a package, the *package 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, TODO: Create are more detailed reference page for package and library layout,

+ 9
- 0
docs/err/invalid-pkg-manifest.rst View File

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.

+ 1
- 1
docs/err/test-failure.rst View File



This error message is printed when a project's tests encounter a failure 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 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 If you see this error, it is most likely that you have an issue in the tests of
your project. your project.

+ 4
- 4
docs/err/unknown-test-driver.rst View File

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 that the driver you want to use is supported by ``dds``. Refer to the
:doc:`/guide/packages` page. :doc:`/guide/packages` page.

+ 3
- 3
docs/err/unknown-usage.rst View File

######################################### #########################################


A library can declare that it *uses* or *links* to another library by using the 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 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 known library, ``dds`` will not be able to resolve the usage requirements, and
will generate an error. will generate an error.



+ 7
- 7
docs/guide/catalog.rst View File

dds catalog add <package-id> dds catalog add <package-id>
[--depends <requirement> [--depends <requirement> [...]]] [--depends <requirement> [--depends <requirement> [...]]]
[--git-url <url> --git-ref <ref>] [--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 The ``<package-id>`` positional arguments is the ``name@version`` package ID
that will be added to the catalog. The following options are supported: that will be added to the catalog. The following options are supported:
``--depends <requirement>`` ``--depends <requirement>``
This argument, which can be specified multiple times to represent multiple This argument, which can be specified multiple times to represent multiple
dependencies, sets the dependencies of the package within the catalog. If 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>`` ``--git-url <url>``
Specify a Git URL to clone from to obtain the package. The root of the 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 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. ``--auto-lib`` parameter.


``--git-ref`` **must** be passed with ``--git-url``. ``--git-ref`` **must** be passed with ``--git-url``.
can only be specified for packages that contain a single library root at can only be specified for packages that contain a single library root at
the package root. 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. generated for the library.





+ 60
- 47
docs/guide/interdeps.rst View File

******************** ********************


Consider that we are creating a package ``acme-gadgets@4.3.6``. We declare the 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:: .. 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. :ref:`deps.lib-deps` section.


Suppose that our package's libraries build upon the libraries in the 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`` not as new as ``2.0.0``. Such a dependency can be declared with the ``Depends``
key: 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`. .. seealso:: :ref:`deps.ranges`.


additional ``Depends`` keys additional ``Depends`` keys


.. code-block:: .. 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 When ``dds`` attempts to build a project, it will first build the dependency
solution by iteratively scanning the dependencies of the containing project and solution by iteratively scanning the dependencies of the containing project and


In ``dds``, library interdependencies are tracked separately from the packages In ``dds``, library interdependencies are tracked separately from the packages
that contain them. A library must declare its intent to use another library 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 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. 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:: .. 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``. to a C++ ``namespace``.


.. note:: .. 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. 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! 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 will make available the headers for the library being used, and will
transitively propagate that usage requirement to users of the library. transitively propagate that usage requirement to users of the library.

+ 22
- 18
docs/guide/packages.rst View File

A *test* source file is a source file whose file stem ends with ``.test``. Like 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 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 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`` source file will generate a single test executable that is executed by ``dds``
when running unit tests. when running unit tests.


dependencies of a header-only library. dependencies of a header-only library.


In order for ``dds`` to be able to distribute and interlink libraries, a 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 .. seealso:: More information is discussed on the :ref:`deps.lib-deps` page


within a repository or package catalog. within a repository or package catalog.


In order for a package to be exported by ``dds`` it must have a 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:: .. 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:: .. 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 are described in the :ref:`deps.pkg-deps` page




Package names aren't a complete free-for-all. Package names must follow a set Package names aren't a complete free-for-all. Package names must follow a set
of specific rules: 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:: .. note::
Different filesystems differ in their handling of filenames. Some platforms Different filesystems differ in their handling of filenames. Some platforms

+ 2
- 2
docs/guide/repo.rst View File

$ ls ./spdlog@1.4.2/ $ ls ./spdlog@1.4.2/
include/ include/
src/ src/
library.dds
package.dds
library.json5
package.json5




.. _repo.export-local: .. _repo.export-local:

+ 11
- 10
docs/tut/hello-test.rst View File

diagnostics? diagnostics?




A ``Test-Driver``: Using *Catch2*
A ``test_driver``: Using *Catch2*
********************************* *********************************


``dds`` ships with built-in support for the `Catch2`_ C and C++ testing ``dds`` ships with built-in support for the `Catch2`_ C and C++ testing
.. _catch2: https://github.com/catchorg/Catch2 .. _catch2: https://github.com/catchorg/Catch2


To make use of Catch as our test driver, we simply declare this intent in the 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 :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 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 compile an entrypoint separately from any particular test, and the tests
will link against that entrypoint. This means we cannot provide our own will link against that entrypoint. This means we cannot provide our own
``main`` function, and should instead use Catch's ``TEST_CASE`` macro to ``main`` function, and should instead use Catch's ``TEST_CASE`` macro to

+ 9
- 8
docs/tut/hello-world.rst View File



``dds`` will work happily with packages that do not declare themselves, as long ``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 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 information about are package. This file should be placed directly in the
package root: 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:: .. 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. Rebuilding the project will show no difference at the moment.



+ 2
- 0
library.dds View File

Uses: neo/sqlite3 Uses: neo/sqlite3
Uses: neo/fun Uses: neo/fun
Uses: semver/semver Uses: semver/semver
Uses: vob/semester
Uses: pubgrub/pubgrub Uses: pubgrub/pubgrub
Uses: vob/json5

+ 16
- 0
library.jsonc View File

{
"$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",
]
}

+ 3
- 1
package.dds View File

Depends: neo-fun 0.1.0 Depends: neo-fun 0.1.0
Depends: semver 0.2.1 Depends: semver 0.2.1
Depends: pubgrub 0.2.0 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

+ 19
- 0
package.jsonc View File

{
"$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"
}

+ 34
- 0
res/library-schema.json View File

{
"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_]+)*$"
}
}
}
}

+ 53
- 0
res/package-schema.json View File

{
"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"
]
}
}
}

+ 183
- 0
res/toolchain-schema.json View File

{
"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"
}
}
}
}
}

+ 6
- 7
src/dds.main.cpp View File

#include <dds/error/errors.hpp> #include <dds/error/errors.hpp>
#include <dds/repo/repo.hpp> #include <dds/repo/repo.hpp>
#include <dds/source/dist.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/fs.hpp>
#include <dds/util/paths.hpp> #include <dds/util/paths.hpp>
#include <dds/util/signal.hpp> #include <dds/util/signal.hpp>
} }
return std::move(*tc); return std::move(*tc);
} else { } 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));
} }
} }
}; };
params.out_root = out.Get(); params.out_root = out.Get();
params.toolchain = tc_filepath.get_toolchain(); params.toolchain = tc_filepath.get_toolchain();
params.parallel_jobs = n_jobs.Get(); 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::builder bd;
dds::sdist_build_params main_params; dds::sdist_build_params main_params;

+ 15
- 6
src/dds/catalog/get.cpp View File

#include <dds/error/errors.hpp> #include <dds/error/errors.hpp>
#include <dds/proc.hpp> #include <dds/proc.hpp>


#include <nlohmann/json.hpp>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>


using namespace dds; using namespace dds;
spdlog::info("Create sdist from clone ..."); spdlog::info("Create sdist from clone ...");
if (git.auto_lib.has_value()) { if (git.auto_lib.has_value()) {
spdlog::info("Generating library data automatically"); 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; sdist_params params;

+ 32
- 13
src/dds/error/errors.cpp View File

return "sdist-ident-mismatch.html"; return "sdist-ident-mismatch.html";
case errc::corrupted_build_db: case errc::corrupted_build_db:
return "corrupted-build-db.html"; 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: case errc::invalid_version_range_string:
return "invalid-version-string.html#range"; return "invalid-version-string.html#range";
case errc::invalid_version_string: case errc::invalid_version_string:
The catalog database schema doesn't match what dds expects. This indicates that 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 the database file has been modified in a way that dds cannot automatically fix
and handle. 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: case errc::invalid_catalog_json:
return R"( return R"(
)"; )";
case errc::unknown_usage_name: case errc::unknown_usage_name:
return R"( 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 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. for the build.
)"; )";
case errc::none: case errc::none:
"that was expected of it"; "that was expected of it";
case errc::corrupted_build_db: case errc::corrupted_build_db:
return "The build database file is corrupted"; 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: case errc::invalid_version_range_string:
return "Attempted to parse an invalid version range string. <- (Seeing this text is a " return "Attempted to parse an invalid version range string. <- (Seeing this text is a "
"`dds` bug. Please report it.)"; "`dds` bug. Please report it.)";
case errc::invalid_version_string: 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: 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_lib_filesystem:
case errc::invalid_pkg_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: case errc::invalid_pkg_id:
return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please " return "A package identifier is invalid <- (Seeing this text is a `dds` bug. Please "
"report it.)"; "report it.)";
case errc::invalid_pkg_name: 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: 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: 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: case errc::dependency_resolve_failure:
return "`dds` was unable to find a solution for the package dependencies given."; return "`dds` was unable to find a solution for the package dependencies given.";
case errc::dup_lib_name: case errc::dup_lib_name:
return "More than one library has claimed the same name."; return "More than one library has claimed the same name.";
case errc::unknown_usage_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: case errc::none:
break; break;
} }

+ 2
- 0
src/dds/error/errors.hpp View File



corrupted_build_db, corrupted_build_db,


invalid_lib_manifest,
invalid_pkg_manifest,
invalid_version_range_string, invalid_version_range_string,
invalid_version_string, invalid_version_string,
invalid_pkg_id, invalid_pkg_id,

+ 113
- 4
src/dds/library/manifest.cpp View File

#include "./manifest.hpp" #include "./manifest.hpp"


#include <dds/dym.hpp> #include <dds/dym.hpp>
#include <dds/error/errors.hpp>
#include <dds/util/algo.hpp> #include <dds/util/algo.hpp>
#include <range/v3/view/transform.hpp>

#include <libman/parse.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; 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); auto kvs = lm::parse_file(fpath);
library_manifest ret; library_manifest ret;
ret.name = fpath.parent_path().filename().string(); ret.name = fpath.parent_path().filename().string();
extend(ret.links, ranges::views::transform(links_strings, lm::split_usage_string)); extend(ret.links, ranges::views::transform(links_strings, lm::split_usage_string));
return ret; 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);
}
}

+ 12
- 3
src/dds/library/manifest.hpp View File

namespace dds { 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 * 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 { struct library_manifest {
/// The name of the library /// The name of the library
/** /**
* Load the library manifest from an existing file * 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 } // namespace dds

+ 8
- 4
src/dds/library/root.cpp View File

auto sources = collect_pf_sources(lib_dir); auto sources = collect_pf_sources(lib_dir);


library_manifest man; 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)); auto lib = library_root(lib_dir, std::move(sources), std::move(man));

+ 137
- 3
src/dds/package/manifest.cpp View File

#include <range/v3/view/split.hpp> #include <range/v3/view/split.hpp>
#include <range/v3/view/split_when.hpp> #include <range/v3/view/split_when.hpp>
#include <range/v3/view/transform.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; 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); auto kvs = lm::parse_file(fpath);
package_manifest ret; package_manifest ret;
std::string version_str; std::string version_str;
} else { } else {
auto dym = *did_you_mean(test_driver_str, {"Catch-Main", "Catch"}); auto dym = *did_you_mean(test_driver_str, {"Catch-Main", "Catch"});
throw_user_error< 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, test_driver_str,
dym); dym);
} }


return ret; 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
- 2
src/dds/package/manifest.hpp View File

namespace dds { namespace dds {


/** /**
* Possible values for Test-Driver in a package.dds
* Possible values for test_driver in a package.json5
*/ */
enum class test_lib { enum class test_lib {
catch_, catch_,
package_id pkg_id; package_id pkg_id;
/// The declared `Namespace` of the package. This directly corresponds with the libman Namespace /// The declared `Namespace` of the package. This directly corresponds with the libman Namespace
std::string 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; std::optional<test_lib> test_driver;
/// The dependencies declared with the `Depends` fields, if any. /// The dependencies declared with the `Depends` fields, if any.
std::vector<dependency> dependencies; std::vector<dependency> dependencies;
* Load a package manifest from a file on disk. * Load a package manifest from a file on disk.
*/ */
static package_manifest load_from_file(path_ref); 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 } // namespace dds

+ 18
- 16
src/dds/source/dist.cpp View File



ranges::sort(sources_to_keep, std::less<>(), [](auto&& s) { return s.path; }); 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>( 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()); spdlog::info("sdist: Export library from {}", lib.path().string());
fs::create_directories(out_root); fs::create_directories(out_root);
sdist_copy_library(out, lib, 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>( 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()); spdlog::info("Generated export as {}", pkg_man.pkg_id.to_string());

return sdist::from_directory(out); return sdist::from_directory(out);
} }


sdist sdist::from_directory(path_ref where) { 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};
} }

+ 0
- 18
src/dds/toolchain/from_dds.hpp View File

#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

src/dds/toolchain/from_dds.cpp → src/dds/toolchain/from_json.cpp View File

#include "./from_dds.hpp"
#include "./from_json.hpp"


#include <dds/dym.hpp> #include <dds/dym.hpp>
#include <dds/error/errors.hpp>
#include <dds/toolchain/prep.hpp> #include <dds/toolchain/prep.hpp>
#include <dds/toolchain/toolchain.hpp>
#include <dds/util/algo.hpp> #include <dds/util/algo.hpp>
#include <dds/util/shlex.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 <spdlog/fmt/fmt.h>


#include <map>
#include <optional>
#include <tuple>
#include <vector>
#include <string>


using namespace dds; using namespace dds;


using fmt::format;
using std::optional; using std::optional;
using std::string; using std::string;
using std::vector; 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 { 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> template <typename T, typename Func>
T read_opt(const std::optional<T>& what, Func&& fn) { T read_opt(const std::optional<T>& what, Func&& fn) {


template <typename... Args> template <typename... Args>
[[noreturn]] void fail(strv context, strv message, Args&&... 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 } // 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 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 c_version;
opt_string cxx_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_prefix;
opt_string archive_suffix; opt_string archive_suffix;
opt_string obj_prefix; opt_string obj_prefix;
opt_string obj_suffix; opt_string obj_suffix;
opt_string exe_prefix; opt_string exe_prefix;
opt_string exe_suffix; 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 { enum compiler_id_e_t {
no_comp_id, no_comp_id,
= [&] { = [&] {
if (!compiler_id) { if (!compiler_id) {
return no_comp_id; return no_comp_id;
} else if (compiler_id == "MSVC") {
} else if (compiler_id == "msvc") {
return msvc; return msvc;
} else if (compiler_id == "GNU") {
} else if (compiler_id == "gnu") {
return gnu; return gnu;
} else if (compiler_id == "Clang") {
} else if (compiler_id == "clang") {
return clang; return clang;
} else { } else {
fail(context, "Unknown Compiler-ID '{}'", *compiler_id);
fail(context, "Invalid `compiler_id` value ‘{}’", *compiler_id);
} }
}(); }();


} else { } else {
return file_deps_mode::none; return file_deps_mode::none;
} }
} else if (deps_mode_str == "GNU") {
} else if (deps_mode_str == "gnu") {
return file_deps_mode::gnu; return file_deps_mode::gnu;
} else if (deps_mode_str == "MSVC") {
} else if (deps_mode_str == "msvc") {
return file_deps_mode::msvc; return file_deps_mode::msvc;
} else if (deps_mode_str == "None") {
} else if (deps_mode_str == "none") {
return file_deps_mode::none; return file_deps_mode::none;
} else { } 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 // 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()) { 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) { if (is_gnu) {
return (lang == language::cxx) ? "g++" : "gcc"; return (lang == language::cxx) ? "g++" : "gcc";
std::terminate(); std::terminate();
}; };


// Determine the C language version
enum c_version_e_t { enum c_version_e_t {
c_none, c_none,
c89, c89,
= [&] { = [&] {
if (!c_version) { if (!c_version) {
return c_none; return c_none;
} else if (c_version == "C89") {
} else if (c_version == "c89") {
return c89; return c89;
} else if (c_version == "C99") {
} else if (c_version == "c99") {
return c99; return c99;
} else if (c_version == "C11") {
} else if (c_version == "c11") {
return c11; return c11;
} else if (c_version == "C18") {
} else if (c_version == "c18") {
return c18; return c18;
} else { } else {
fail(context, "Unknown C-Version '{}'", *c_version);
fail(context, "Unknown `c_version` ‘{}’", *c_version);
} }
}(); }();


= [&] { = [&] {
if (!cxx_version) { if (!cxx_version) {
return cxx_none; return cxx_none;
} else if (cxx_version == "C++98") {
} else if (cxx_version == "c++98") {
return cxx98; return cxx98;
} else if (cxx_version == "C++03") {
} else if (cxx_version == "c++03") {
return cxx03; return cxx03;
} else if (cxx_version == "C++11") {
} else if (cxx_version == "c++11") {
return cxx11; return cxx11;
} else if (cxx_version == "C++14") {
} else if (cxx_version == "c++14") {
return cxx14; return cxx14;
} else if (cxx_version == "C++17") {
} else if (cxx_version == "c++17") {
return cxx17; return cxx17;
} else if (cxx_version == "C++20") {
} else if (cxx_version == "c++20") {
return cxx20; return cxx20;
} else { } else {
fail(context, "Unknown C++-Version '{}'", *cxx_version);
fail(context, "Unknown `cxx_version` ‘{}’", *cxx_version);
} }
}(); }();




auto get_c_version_flags = [&]() -> string_seq { auto get_c_version_flags = [&]() -> string_seq {
if (!compiler_id.has_value()) { 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}); auto c_ver_iter = c_version_flag_table.find({compiler_id_e, c_version_e});
assert(c_ver_iter != c_version_flag_table.end()); assert(c_ver_iter != c_version_flag_table.end());


auto get_cxx_version_flags = [&]() -> string_seq { auto get_cxx_version_flags = [&]() -> string_seq {
if (!compiler_id.has_value()) { 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}); auto cxx_ver_iter = cxx_version_flag_table.find({compiler_id_e, cxx_version_e});
assert(cxx_ver_iter != cxx_version_flag_table.end()); assert(cxx_ver_iter != cxx_version_flag_table.end());


auto get_flags = [&](language lang) -> string_seq { auto get_flags = [&](language lang) -> string_seq {
string_seq ret; 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) { if (is_msvc) {
strv rt_lib = "/MT"; strv rt_lib = "/MT";
if (do_optimize.has_value() && *do_optimize) { if (do_optimize.has_value() && *do_optimize) {
"<IN>", "<IN>",
"-o<OUT>"}); "-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; return ret;
}; };


toolchain_prep tc;
tc.deps_mode = deps_mode; tc.deps_mode = deps_mode;

tc.c_compile = read_opt(c_compile_file, [&] { tc.c_compile = read_opt(c_compile_file, [&] {
string_seq c; 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)); extend(c, get_flags(language::c));
return c; return c;
}); });


tc.cxx_compile = read_opt(cxx_compile_file, [&] { tc.cxx_compile = read_opt(cxx_compile_file, [&] {
string_seq cxx; 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)); extend(cxx, get_flags(language::cxx));
return cxx; return cxx;
}); });


tc.include_template = read_opt(include_template, [&]() -> string_seq { tc.include_template = read_opt(include_template, [&]() -> string_seq {
if (!compiler_id) { 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) { if (is_gnu_like) {
return {"-I", "<PATH>"}; return {"-I", "<PATH>"};
} else if (is_msvc) { } else if (is_msvc) {
return {"/I", "<PATH>"}; return {"/I", "<PATH>"};
} }
assert(false && "Include-Template deduction failed");
assert(false && "'include_template' deduction failed");
std::terminate(); std::terminate();
}); });


// MSVC has external-header support inbound, but it is not fully ready yet // MSVC has external-header support inbound, but it is not fully ready yet
return {"/I", "<PATH>"}; return {"/I", "<PATH>"};
} }
assert(false && "External-Include-Template deduction failed");
assert(false && "external_include_template deduction failed");
std::terminate(); std::terminate();
}); });


tc.define_template = read_opt(define_template, [&]() -> string_seq { tc.define_template = read_opt(define_template, [&]() -> string_seq {
if (!compiler_id) { 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) { if (is_gnu_like) {
return {"-D", "<DEF>"}; return {"-D", "<DEF>"};
} else if (is_msvc) { } else if (is_msvc) {
return {"/D", "<DEF>"}; return {"/D", "<DEF>"};
} }
assert(false && "Define-Template deduction failed");
assert(false && "define_template deduction failed");
std::terminate(); std::terminate();
}); });


#endif #endif
}); });


/// TODO: Handle base_warning_flags:
tc.warning_flags = read_opt(warning_flags, [&]() -> string_seq { tc.warning_flags = read_opt(warning_flags, [&]() -> string_seq {
if (!compiler_id) { if (!compiler_id) {
// No error. Just no warning flags // No error. Just no warning flags


tc.link_archive = read_opt(create_archive, [&]() -> string_seq { tc.link_archive = read_opt(create_archive, [&]() -> string_seq {
if (!compiler_id) { 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) { if (is_msvc) {
return {"lib", "/nologo", "/OUT:<OUT>", "<IN>"}; return {"lib", "/nologo", "/OUT:<OUT>", "<IN>"};


tc.link_exe = read_opt(link_executable, [&]() -> string_seq { tc.link_exe = read_opt(link_executable, [&]() -> string_seq {
if (!compiler_id) { 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; string_seq ret;
if (is_msvc) { 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) { } else if (is_gnu_like) {
ret = {get_compiler(language::cxx),
ret = {get_compiler_executable_path(language::cxx),
"-fPIC", "-fPIC",
"-fdiagnostics-color", "-fdiagnostics-color",
"<IN>", "<IN>",
}); });


return tc.realize(); return tc.realize();
}
}

+ 17
- 0
src/dds/toolchain/from_json.hpp View File

#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

src/dds/toolchain/from_dds.test.cpp → src/dds/toolchain/from_json.test.cpp View File

#include <dds/toolchain/from_dds.hpp>
#include <dds/toolchain/from_json.hpp>


#include <dds/proc.hpp> #include <dds/proc.hpp>


// #include <dds/util.test.hpp>
#include <catch2/catch.hpp> #include <catch2/catch.hpp>


namespace { namespace {

void check_tc_compile(std::string_view tc_content, void check_tc_compile(std::string_view tc_content,
std::string_view expected_compile, std::string_view expected_compile,
std::string_view expected_compile_warnings, std::string_view expected_compile_warnings,
std::string_view expected_ar, std::string_view expected_ar,
std::string_view expected_exe) { 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; dds::compile_file_spec cf;
cf.source_path = "foo.cpp"; cf.source_path = "foo.cpp";
CHECK(exe_cmd_str == expected_exe); CHECK(exe_cmd_str == expected_exe);
} }


} // namespace

TEST_CASE("Generating toolchain commands") { TEST_CASE("Generating toolchain commands") {
check_tc_compile( 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 -MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o",
"g++ -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " "g++ -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion "
"-MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o", "-MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o",
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe"); "g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe");


check_tc_compile( 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 -MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o",
"g++ -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " "g++ -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion "
"-MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o", "-MD -MF foo.o.d -MT foo.o -c foo.cpp -ofoo.o",
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe -g"); "g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe -g");


check_tc_compile( 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 " "g++ -O2 -g -fPIC -fdiagnostics-color -pthread -MD -MF foo.o.d -MT foo.o -c foo.cpp "
"-ofoo.o", "-ofoo.o",
"g++ -O2 -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion " "g++ -O2 -g -fPIC -fdiagnostics-color -pthread -Wall -Wextra -Wpedantic -Wconversion "
"ar rcs stuff.a foo.o bar.o", "ar rcs stuff.a foo.o bar.o",
"g++ -fPIC -fdiagnostics-color foo.o bar.a -pthread -omeow.exe -O2 -g"); "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- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /MT /EHsc /nologo /permissive- /W4 /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", "lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT"); "cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /MT");


check_tc_compile( 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- /showIncludes /c foo.cpp /Fofoo.o",
"cl.exe /Z7 /DEBUG /MTd /EHsc /nologo /permissive- /W4 /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", "lib /nologo /OUT:stuff.a foo.o bar.o",
"cl.exe /nologo /EHsc foo.o bar.a /Femeow.exe /Z7 /DEBUG /MTd"); "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; dds::compile_file_spec cfs;
cfs.source_path = "foo.cpp"; cfs.source_path = "foo.cpp";
"-c", "-c",
"foo.cpp", "foo.cpp",
"-ofoo.o"}); "-ofoo.o"});
}

} // namespace
}

+ 30
- 23
src/dds/toolchain/toolchain.cpp View File

#include "./toolchain.hpp" #include "./toolchain.hpp"


#include <dds/toolchain/from_dds.hpp>
#include <dds/toolchain/from_json.hpp>
#include <dds/toolchain/prep.hpp> #include <dds/toolchain/prep.hpp>
#include <dds/util/algo.hpp> #include <dds/util/algo.hpp>
#include <dds/util/paths.hpp> #include <dds/util/paths.hpp>
std::optional<toolchain> toolchain::get_builtin(std::string_view tc_id) noexcept { std::optional<toolchain> toolchain::get_builtin(std::string_view tc_id) noexcept {
using namespace std::literals; 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:")) { if (starts_with(tc_id, "debug:")) {
tc_id = tc_id.substr("debug:"sv.length()); tc_id = tc_id.substr("debug:"sv.length());
tc_content += "Debug: True\n";
root_map.emplace("debug", true);
} }


if (starts_with(tc_id, "ccache:")) { if (starts_with(tc_id, "ccache:")) {
tc_id = tc_id.substr("ccache:"sv.length()); 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) \ #define CXX_VER_TAG(str, version) \
if (starts_with(tc_id, str)) { \ if (starts_with(tc_id, str)) { \
tc_id = tc_id.substr(std::string_view(str).length()); \ 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) 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 { struct compiler_info {
string c; string c;


const auto [c_compiler_base, cxx_compiler_base, compiler_id] = [&]() -> compiler_info { const auto [c_compiler_base, cxx_compiler_base, compiler_id] = [&]() -> compiler_info {
if (is_gcc) { if (is_gcc) {
return {"gcc", "g++", "GNU"};
return {"gcc", "g++", "gnu"};
} else if (is_clang) { } else if (is_clang) {
return {"clang", "clang++", "Clang"};
return {"clang", "clang++", "clang"};
} }
assert(false && "Unreachable"); assert(false && "Unreachable");
std::terminate(); std::terminate();
auto cxx_compiler_name = cxx_compiler_base + compiler_suffix; auto cxx_compiler_name = cxx_compiler_base + compiler_suffix;
return compiler_info{c_compiler_name, cxx_compiler_name, compiler_id}; return compiler_info{c_compiler_name, cxx_compiler_name, compiler_id};
} else if (tc_id == "msvc") { } else if (tc_id == "msvc") {
return compiler_info{"cl.exe", "cl.exe", "MSVC"};
return compiler_info{"cl.exe", "cl.exe", "msvc"};
} else { } else {
return std::nullopt; return std::nullopt;
} }
return std::nullopt; 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() { std::optional<dds::toolchain> dds::toolchain::get_default() {
auto candidates = { 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) { for (auto&& cand : candidates) {
if (fs::exists(cand)) { if (fs::exists(cand)) {
return parse_toolchain_dds(slurp_file(cand));
return parse_toolchain_json5(slurp_file(cand));
} }
} }
return std::nullopt; return std::nullopt;
}
}

+ 6
- 3
tests/basics/test_basics.py View File



def basic_pkg_dds(dds: DDS): def basic_pkg_dds(dds: DDS):
return set_contents( 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',
}
''') ''')





+ 6
- 2
tests/catalog/get_test.py View File

from tests import dds, DDS from tests import dds, DDS
from tests.fileutil import ensure_dir from tests.fileutil import ensure_dir


import pytest



def test_get(dds: DDS): def test_get(dds: DDS):
dds.scope.enter_context(ensure_dir(dds.build_dir)) dds.scope.enter_context(ensure_dir(dds.build_dir))
'0.2.2': { '0.2.2': {
'depends': {}, 'depends': {},
'git': { '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',
}, },
}, },
}, },

+ 1
- 1
tests/deps/git-remote/catalog.json View File

"0.1.0": { "0.1.0": {
"git": { "git": {
"url": "https://github.com/vector-of-bool/neo-buffer.git", "url": "https://github.com/vector-of-bool/neo-buffer.git",
"ref": "develop"
"ref": "0.1.0"
}, },
"depends": {} "depends": {}
} }

+ 0
- 5
tests/deps/git-remote/package.dds View File

Name: deps-test
Version: 0.0.0

Depends: neo-buffer 0.1.0
Depends: range-v3 0.9.1

+ 9
- 0
tests/deps/git-remote/package.json5 View File

{
name: 'deps-test',
"namespace": "test",
version: '0.0.0',
depends: {
'neo-buffer': '0.1.0',
'range-v3': '0.9.1',
}
}

+ 0
- 2
tests/deps/no-deps/package.dds View File

Name: deps-test
Version: 0.0.0

+ 5
- 0
tests/deps/no-deps/package.json5 View File

{
name: 'deps-test',
version: '0.0.0',
"namespace": "test",
}

+ 0
- 3
tests/deps/use-remote/library.dds View File

Name: dummy

Uses: nlohmann/json

+ 6
- 0
tests/deps/use-remote/library.json5 View File

{
name: "dummy",
uses: [
'nlohmann/json',
]
}

+ 0
- 4
tests/deps/use-remote/package.dds View File

Name: json-test
Version: 0.0.0

Depends: nlohmann-json 3.7.1

+ 8
- 0
tests/deps/use-remote/package.json5 View File

{
"name": "json-test",
"version": "0.0.0",
"namespace": "test",
"depends": {
"nlohmann-json": "3.7.1"
}
}

+ 6
- 0
tests/deps/use-spdlog/gcc.tc.jsonc View File

{
"compiler_id": 'gnu',
"cxx_version": 'c++17',
"cxx_compiler": 'g++-9',
"flags": '-DSPDLOG_COMPILED_LIB',
}

+ 4
- 0
tests/deps/use-spdlog/msvc.tc.jsonc View File

{
"compiler_id": 'msvc',
"flags": '-DSPDLOG_COMPILED_LIB',
}

+ 0
- 3
tests/deps/use-spdlog/project/library.dds View File

Name: spdlog-user

Uses: spdlog/spdlog

+ 6
- 0
tests/deps/use-spdlog/project/library.json5 View File

{
name: 'spdlog-user',
uses: [
'spdlog/spdlog',
]
}

+ 0
- 4
tests/deps/use-spdlog/project/package.dds View File

Name: test
Version: 0.0.0

Depends: spdlog 1.4.2

+ 8
- 0
tests/deps/use-spdlog/project/package.json5 View File

{
name: 'test',
version: '0.0.0',
"namespace": "test",
depends: {
'spdlog': '1.4.2',
},
}

+ 1
- 1
tests/deps/use-spdlog/use_spdlog_test.py View File



def test_get_build_use_spdlog(dds: DDS): def test_get_build_use_spdlog(dds: DDS):
dds.catalog_import(dds.source_root / 'catalog.json') 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) tc = str(dds.test_dir / tc_fname)
dds.build(toolchain=tc, apps=True) dds.build(toolchain=tc, apps=True)
proc.check_run((dds.build_dir / 'use-spdlog').with_suffix(dds.exe_suffix)) proc.check_run((dds.build_dir / 'use-spdlog').with_suffix(dds.exe_suffix))

+ 0
- 1
tests/sdist/create/library.dds View File

Name: foo

+ 3
- 0
tests/sdist/create/library.jsonc View File

{
"name": "foo"
}

+ 0
- 2
tests/sdist/create/package.dds View File

Name: foo
Version: 1.2.3

+ 5
- 0
tests/sdist/create/package.json5 View File

{
name: 'foo',
version: '1.2.3',
"namespace": "test",
}

+ 0
- 4
tests/test_drivers/catch/custom-runner/package.dds View File

Name: Test
Version: 0.0.0

Test-Driver: Catch

+ 6
- 0
tests/test_drivers/catch/custom-runner/package.json5 View File

{
"name": "test",
"version": "0.0.0",
"namespace": "test",
"test_driver": "Catch",
}

+ 0
- 4
tests/test_drivers/catch/main/package.dds View File

Name: Test
Version: 0.0.0

Test-Driver: Catch-Main

+ 6
- 0
tests/test_drivers/catch/main/package.json5 View File

{
"name": "test",
"version": "0.0.0",
"namespace": "test",
"test_driver": "Catch-Main",
}

+ 10
- 2
tools/ci.py View File



class CIOptions(NamedTuple): class CIOptions(NamedTuple):
toolchain: str toolchain: str
toolchain_json5: str




def _do_bootstrap_build(opts: CIOptions) -> None: def _do_bootstrap_build(opts: CIOptions) -> None:
'-T', '-T',
help='The toolchain to use for the CI process', help='The toolchain to use for the CI process',
required=True) 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) 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': if args.bootstrap_with == 'build':
_do_bootstrap_build(opts) _do_bootstrap_build(opts)
]) ])
self_build( self_build(
paths.CUR_BUILT_DDS, paths.CUR_BUILT_DDS,
toolchain=opts.toolchain,
toolchain=opts.toolchain_json5,
dds_flags=[f'--repo-dir={ci_repo_dir}', f'--catalog={cat_path}']) dds_flags=[f'--repo-dir={ci_repo_dir}', f'--catalog={cat_path}'])
print('Bootstrap test PASSED!') print('Bootstrap test PASSED!')



+ 3
- 3
tools/gcc-9.dds View File

# Range-v3 0.10.0 contains an accidental conversion warning # Range-v3 0.10.0 contains an accidental conversion warning
Flags: -D SPDLOG_COMPILED_LIB -Werror=return-type -Wno-conversion Flags: -D SPDLOG_COMPILED_LIB -Werror=return-type -Wno-conversion
C++-Flags: -fconcepts 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 Compiler-Launcher: ccache

+ 17
- 0
tools/gcc-9.jsonc View File

{
"$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"
}

+ 18
- 1
tools/gen-catalog-json.py View File

ret: dict = { ret: dict = {
'description': self.description, 'description': self.description,
} }
ret['depends'] = {}
ret['depends'] = self.depends
if isinstance(self.remote, Git): if isinstance(self.remote, Git):
ret['git'] = self.remote.to_dict() ret['git'] = self.remote.to_dict()
return ret return ret
'A C++ implementation of the Pubgrub version solving algorithm', 'A C++ implementation of the Pubgrub version solving algorithm',
git_url='https://github.com/vector-of-bool/pubgrub.git', 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( many_versions(
'spdlog', 'spdlog',
( (

+ 14
- 0
tools/msvc.jsonc View File

{
"$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
}

Loading…
Cancel
Save