Hello libcode-build
This commit is contained in:
commit
5fa111c2a3
16
.editorconfig
Normal file
16
.editorconfig
Normal file
@ -0,0 +1,16 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
end_of_line = lf
|
||||
|
||||
[*.md]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
* text=auto
|
24
.gitea/workflows/on-push.yaml
Normal file
24
.gitea/workflows/on-push.yaml
Normal file
@ -0,0 +1,24 @@
|
||||
name: on-push
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: linux
|
||||
container: code.helloryan.se/infra/buildenv/cxx-amd64-fedora-40:latest
|
||||
volumes:
|
||||
- /build
|
||||
steps:
|
||||
- name: Clone repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Authenticate
|
||||
run: |
|
||||
git config unset http.https://code.helloryan.se/.extraheader
|
||||
echo "${{ secrets.NETRC }}" >> ~/.netrc
|
||||
- name: Initialize
|
||||
run: |
|
||||
bpkg create -d /build cc config.cc.coptions="-Wall -Werror"
|
||||
bdep init -A /build
|
||||
- name: Build
|
||||
run: b
|
||||
- name: Test
|
||||
run: b test
|
31
.gitignore
vendored
Normal file
31
.gitignore
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
.bdep/
|
||||
|
||||
# Local default options files.
|
||||
#
|
||||
.build2/local/
|
||||
|
||||
# Compiler/linker output.
|
||||
#
|
||||
*.d
|
||||
*.t
|
||||
*.i
|
||||
*.i.*
|
||||
*.ii
|
||||
*.ii.*
|
||||
*.o
|
||||
*.obj
|
||||
*.gcm
|
||||
*.pcm
|
||||
*.ifc
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
*.a
|
||||
*.lib
|
||||
*.exp
|
||||
*.pdb
|
||||
*.ilk
|
||||
*.exe
|
||||
*.exe.dlls/
|
||||
*.exe.manifest
|
||||
*.pc
|
31
LICENSE
Normal file
31
LICENSE
Normal file
@ -0,0 +1,31 @@
|
||||
Copyright © 2024 Ryan. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. All advertising materials mentioning features or use of this software must
|
||||
display the following acknowledgement:
|
||||
|
||||
This product includes software developed by Ryan, http://helloryan.se/.
|
||||
|
||||
4. Neither the name(s) of the copyright holder(s) nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR
|
||||
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21
README.md
Normal file
21
README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# libcode-build
|
||||
|
||||
![Build status](https://code.helloryan.se/code/libcode-build/actions/workflows/on-push.yaml/badge.svg)
|
||||
|
||||
## Requirements
|
||||
|
||||
None, other than a modern C++-compiler.
|
||||
|
||||
## Building
|
||||
|
||||
See the wiki, https://code.helloryan.se/code/wiki/wiki/Build-Instructions, for
|
||||
build instructions.
|
||||
|
||||
## Contact
|
||||
|
||||
Please report bugs and issues by sending an e-mail to: ryan@helloryan.se.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please send an e-mail to ryan@helloryan.se to request an account and
|
||||
write-access to the libcode-build repository.
|
4
build/.gitignore
vendored
Normal file
4
build/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/config.build
|
||||
/root/
|
||||
/bootstrap/
|
||||
build/
|
7
build/bootstrap.build
Normal file
7
build/bootstrap.build
Normal file
@ -0,0 +1,7 @@
|
||||
project = libcode-build
|
||||
|
||||
using version
|
||||
using config
|
||||
using test
|
||||
using install
|
||||
using dist
|
6
build/export.build
Normal file
6
build/export.build
Normal file
@ -0,0 +1,6 @@
|
||||
$out_root/
|
||||
{
|
||||
include code/build/
|
||||
}
|
||||
|
||||
export $out_root/code/build/$import.target
|
16
build/root.build
Normal file
16
build/root.build
Normal file
@ -0,0 +1,16 @@
|
||||
# Uncomment to suppress warnings coming from external libraries.
|
||||
#
|
||||
#cxx.internal.scope = current
|
||||
|
||||
cxx.std = latest
|
||||
|
||||
using cxx
|
||||
|
||||
hxx{*}: extension = hxx
|
||||
ixx{*}: extension = ixx
|
||||
txx{*}: extension = txx
|
||||
cxx{*}: extension = cxx
|
||||
|
||||
# The test target for cross-testing (running tests under Wine, etc).
|
||||
#
|
||||
test.target = $cxx.target
|
5
buildfile
Normal file
5
buildfile
Normal file
@ -0,0 +1,5 @@
|
||||
./: {code/ tests/} doc{README.md} legal{LICENSE} manifest
|
||||
|
||||
# Don't install tests.
|
||||
#
|
||||
tests/: install = false
|
9
code/build/.gitignore
vendored
Normal file
9
code/build/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
# Generated version header.
|
||||
#
|
||||
version.hxx
|
||||
|
||||
# Unit test executables and Testscript output directories
|
||||
# (can be symlinks).
|
||||
#
|
||||
*.test
|
||||
test-*.test
|
399
code/build/abstraction.hxx
Normal file
399
code/build/abstraction.hxx
Normal file
@ -0,0 +1,399 @@
|
||||
#ifndef code__build__abstraction_hxx_
|
||||
#define code__build__abstraction_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
#include <code/build/traits.hxx>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
class initialization_context_t;
|
||||
|
||||
class worker_t
|
||||
{
|
||||
public:
|
||||
template<typename T, typename... Args>
|
||||
worker_t(std::in_place_type_t<T>, Args&&... args)
|
||||
: _worker{new instance_t<T>{forward<Args>(args)...}}
|
||||
{}
|
||||
|
||||
void
|
||||
join()
|
||||
{
|
||||
_worker->join();
|
||||
}
|
||||
|
||||
private:
|
||||
struct abstraction_t
|
||||
{
|
||||
virtual
|
||||
~abstraction_t() noexcept = default;
|
||||
|
||||
virtual
|
||||
void
|
||||
join() = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename W>
|
||||
struct instance_t
|
||||
: abstraction_t
|
||||
{
|
||||
template<typename... Args>
|
||||
instance_t(Args&&... args)
|
||||
: worker{forward<Args>(args)...}
|
||||
{}
|
||||
|
||||
void
|
||||
join() override
|
||||
{
|
||||
worker.join();
|
||||
}
|
||||
|
||||
W worker;
|
||||
};
|
||||
|
||||
unique_ptr<abstraction_t> _worker;
|
||||
|
||||
};
|
||||
|
||||
template<typename W, typename... Args>
|
||||
worker_t
|
||||
make_worker(Args&&... args)
|
||||
{
|
||||
return worker_t{std::in_place_type<W>, forward<Args>(args)...};
|
||||
}
|
||||
|
||||
class augmentation_t
|
||||
{
|
||||
public:
|
||||
template<typename T, typename... Args>
|
||||
augmentation_t(std::in_place_type_t<T>, Args&&... args)
|
||||
: _augmentation{new instance_t<T>{forward<Args>(args)...}}
|
||||
{}
|
||||
|
||||
type_index
|
||||
get_type() const
|
||||
{
|
||||
return _augmentation->get_type();
|
||||
}
|
||||
|
||||
bool
|
||||
can_init()
|
||||
{
|
||||
return _augmentation->can_init();
|
||||
}
|
||||
|
||||
void
|
||||
init(initialization_context_t& context)
|
||||
{
|
||||
_augmentation->init(context);
|
||||
}
|
||||
|
||||
bool
|
||||
can_finalize()
|
||||
{
|
||||
return _augmentation->can_finalize();
|
||||
}
|
||||
|
||||
void
|
||||
finalize(initialization_context_t& context)
|
||||
{
|
||||
_augmentation->finalize(context);
|
||||
}
|
||||
|
||||
bool
|
||||
can_start()
|
||||
{
|
||||
return _augmentation->can_start();
|
||||
}
|
||||
|
||||
worker_t
|
||||
start(initialization_context_t& context)
|
||||
{
|
||||
return _augmentation->start(context);
|
||||
}
|
||||
|
||||
template<typename A>
|
||||
A&
|
||||
cast()
|
||||
{
|
||||
if (auto ptr = dynamic_cast<instance_t<A>*>(_augmentation.get()); ptr) {
|
||||
return ptr->augmentation;
|
||||
}
|
||||
|
||||
throw logic_error{"invalid augmentation type"};
|
||||
}
|
||||
|
||||
private:
|
||||
struct abstraction_t
|
||||
{
|
||||
virtual
|
||||
~abstraction_t() = default;
|
||||
|
||||
virtual
|
||||
type_index
|
||||
get_type() const = 0;
|
||||
|
||||
virtual
|
||||
bool
|
||||
can_init() = 0;
|
||||
|
||||
virtual
|
||||
void
|
||||
init(initialization_context_t&) = 0;
|
||||
|
||||
virtual
|
||||
bool
|
||||
can_finalize() = 0;
|
||||
|
||||
virtual
|
||||
void
|
||||
finalize(initialization_context_t&) = 0;
|
||||
|
||||
virtual
|
||||
bool
|
||||
can_start() = 0;
|
||||
|
||||
virtual
|
||||
worker_t
|
||||
start(initialization_context_t&) = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
struct instance_t : abstraction_t
|
||||
{
|
||||
template<typename... Args>
|
||||
instance_t(Args&&... args)
|
||||
: augmentation{forward<Args>(args)...}
|
||||
{}
|
||||
|
||||
type_index
|
||||
get_type() const override
|
||||
{
|
||||
return typeid(A);
|
||||
}
|
||||
|
||||
bool
|
||||
can_init() override
|
||||
{
|
||||
return traits::augmentation_traits<A>::is_initializable;
|
||||
}
|
||||
|
||||
void
|
||||
init(initialization_context_t& context) override
|
||||
{
|
||||
if constexpr (traits::augmentation_traits<A>::is_initializable) {
|
||||
augmentation.init(context);
|
||||
return;
|
||||
}
|
||||
|
||||
throw logic_error{"attempt to initialize non-intializable augmentation"};
|
||||
}
|
||||
|
||||
bool
|
||||
can_finalize() override
|
||||
{
|
||||
return traits::augmentation_traits<A>::is_finalizable;
|
||||
}
|
||||
|
||||
void
|
||||
finalize(initialization_context_t& context) override
|
||||
{
|
||||
if constexpr (traits::augmentation_traits<A>::is_finalizable) {
|
||||
augmentation.finalize(context);
|
||||
return;
|
||||
}
|
||||
|
||||
throw logic_error{"attempt to finalize non-finalizable augmentation"};
|
||||
}
|
||||
|
||||
bool
|
||||
can_start() override
|
||||
{
|
||||
return traits::augmentation_traits<A>::is_startable;
|
||||
}
|
||||
|
||||
worker_t
|
||||
start(initialization_context_t& context) override
|
||||
{
|
||||
if constexpr (traits::augmentation_traits<A>::is_startable) {
|
||||
return augmentation.start(context);
|
||||
}
|
||||
|
||||
throw logic_error{"attempt to start non-startable augmentation"};
|
||||
}
|
||||
|
||||
A augmentation;
|
||||
|
||||
};
|
||||
|
||||
unique_ptr<abstraction_t> _augmentation;
|
||||
|
||||
};
|
||||
|
||||
class initializer_t
|
||||
{
|
||||
public:
|
||||
template<typename T, typename... Args>
|
||||
initializer_t(std::in_place_type_t<T>, Args&&... args)
|
||||
: initializer_{new instance_t<T>{forward<Args>(args)...}}
|
||||
{}
|
||||
|
||||
type_index
|
||||
get_type() const
|
||||
{
|
||||
return initializer_->get_type();
|
||||
}
|
||||
|
||||
augmentation_t
|
||||
make() const
|
||||
{
|
||||
return initializer_->make();
|
||||
}
|
||||
|
||||
private:
|
||||
struct abstraction_t
|
||||
{
|
||||
virtual
|
||||
~abstraction_t() noexcept = default;
|
||||
|
||||
virtual
|
||||
type_index
|
||||
get_type() const = 0;
|
||||
|
||||
virtual
|
||||
augmentation_t
|
||||
make() const = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct instance_t : abstraction_t
|
||||
{
|
||||
template<typename... Args>
|
||||
instance_t(Args&&... args)
|
||||
: initializer{forward<Args>(args)...}
|
||||
{}
|
||||
|
||||
type_index
|
||||
get_type() const override
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
|
||||
virtual
|
||||
augmentation_t
|
||||
make() const override
|
||||
{
|
||||
return initializer.make();
|
||||
}
|
||||
|
||||
T initializer;
|
||||
};
|
||||
|
||||
unique_ptr<abstraction_t> initializer_;
|
||||
|
||||
};
|
||||
|
||||
class configurator_t
|
||||
{
|
||||
public:
|
||||
template<typename I, typename C, typename... Args>
|
||||
configurator_t(std::in_place_type_t<I>, std::in_place_type_t<C>, Args&&... args)
|
||||
: configurator_{new instance_t<I, C>{forward<Args>(args)...}}
|
||||
{}
|
||||
|
||||
type_index
|
||||
get_interface_type() const
|
||||
{
|
||||
return configurator_->get_interface_type();
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
C&
|
||||
cast()
|
||||
{
|
||||
if (auto ptr = dynamic_cast<interface_t<C>*>(configurator_.get()); ptr) {
|
||||
return ptr->cast_interface();
|
||||
}
|
||||
|
||||
if (auto ptr = dynamic_cast<implementation_t<C>*>(configurator_.get()); ptr) {
|
||||
return ptr->cast();
|
||||
}
|
||||
|
||||
throw logic_error{"invalid configurator type"};
|
||||
}
|
||||
|
||||
private:
|
||||
struct abstraction_t
|
||||
{
|
||||
virtual
|
||||
~abstraction_t() noexcept = default;
|
||||
|
||||
virtual
|
||||
type_index
|
||||
get_interface_type() const = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename I>
|
||||
struct interface_t : abstraction_t
|
||||
{
|
||||
virtual
|
||||
I&
|
||||
cast_interface() = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename C>
|
||||
struct implementation_t
|
||||
{
|
||||
virtual
|
||||
~implementation_t() noexcept = default;
|
||||
|
||||
virtual
|
||||
C&
|
||||
cast() = 0;
|
||||
|
||||
};
|
||||
|
||||
template<typename I, typename C>
|
||||
struct instance_t : interface_t<I>,
|
||||
implementation_t<C>
|
||||
{
|
||||
template<typename... Args>
|
||||
instance_t(Args&&... args)
|
||||
: configurator{forward<Args>(args)...}
|
||||
{}
|
||||
|
||||
type_index
|
||||
get_interface_type() const override
|
||||
{
|
||||
return typeid(I);
|
||||
}
|
||||
|
||||
I&
|
||||
cast_interface() override
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
|
||||
C&
|
||||
cast() override
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
|
||||
C configurator;
|
||||
|
||||
};
|
||||
|
||||
unique_ptr<abstraction_t> configurator_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#endif
|
55
code/build/application.hxx
Normal file
55
code/build/application.hxx
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef code__build__application_hxx_
|
||||
#define code__build__application_hxx_
|
||||
|
||||
#include <code/build/abstraction.hxx>
|
||||
#include <code/build/except.hxx>
|
||||
#include <code/build/initialization-context.hxx>
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
class application_t
|
||||
{
|
||||
public:
|
||||
template<typename... Args>
|
||||
application_t(Args&&...);
|
||||
|
||||
~application_t() noexcept;
|
||||
|
||||
void
|
||||
join();
|
||||
|
||||
template<typename A>
|
||||
A&
|
||||
find_augmentation()
|
||||
{
|
||||
return do_find_augmentation(typeid(A)).template cast<A>();
|
||||
}
|
||||
|
||||
private:
|
||||
class initialization_context_t;
|
||||
|
||||
template<typename A, typename... Args>
|
||||
struct factory_t;
|
||||
|
||||
template<typename... Args>
|
||||
static
|
||||
vector<initializer_t>
|
||||
make_initializers(Args&&...);
|
||||
|
||||
augmentation_t&
|
||||
do_find_augmentation(type_index);
|
||||
|
||||
private:
|
||||
vector<augmentation_t> augmentations_;
|
||||
vector<worker_t> workers_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#include <code/build/application.txx>
|
||||
|
||||
#endif
|
163
code/build/application.txx
Normal file
163
code/build/application.txx
Normal file
@ -0,0 +1,163 @@
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
class application_t<M, Augmentations...>::initialization_context_t
|
||||
: public build::initialization_context_t
|
||||
{
|
||||
public:
|
||||
application_t<M, Augmentations...>& application;
|
||||
|
||||
initialization_context_t(application_t<M, Augmentations...>& app)
|
||||
: application{app}
|
||||
{}
|
||||
|
||||
augmentation_t&
|
||||
do_find_augmentation(type_index type) override
|
||||
{
|
||||
return application.do_find_augmentation(type);
|
||||
}
|
||||
|
||||
configurator_t&
|
||||
do_register_configurator(configurator_t configurator) override
|
||||
{
|
||||
// fixme: ensure interface has not already been configured.
|
||||
//
|
||||
|
||||
auto type = configurator.get_interface_type();
|
||||
return configurators_.emplace(type, move(configurator)).first->second;
|
||||
}
|
||||
|
||||
configurator_t&
|
||||
do_find_configurator(type_index type) override
|
||||
{
|
||||
if (auto it = configurators_.find(type); it != configurators_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
throw invalid_configurator_t{};
|
||||
}
|
||||
|
||||
private:
|
||||
map<type_index, configurator_t> configurators_;
|
||||
|
||||
};
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
template<typename A, typename... Args>
|
||||
struct application_t<M, Augmentations...>::factory_t
|
||||
{
|
||||
std::tuple<Args...> args;
|
||||
|
||||
factory_t(Args&&... args)
|
||||
: args{forward<Args>(args)...}
|
||||
{}
|
||||
|
||||
augmentation_t
|
||||
make() const
|
||||
{
|
||||
auto construct = [&](auto&&... args)
|
||||
{
|
||||
return augmentation_t{std::in_place_type<A>, forward<decltype(args)>(args)...};
|
||||
};
|
||||
|
||||
return std::apply(construct, args);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
template<typename... Args>
|
||||
application_t<M, Augmentations...>::
|
||||
application_t(Args&&... args)
|
||||
{
|
||||
auto initializers = make_initializers(std::forward<Args>(args)...);
|
||||
|
||||
vector<augmentation_t> augmentations;
|
||||
|
||||
for (auto& j : initializers) {
|
||||
augmentations.emplace_back(j.make());
|
||||
}
|
||||
|
||||
initialization_context_t context{*this};
|
||||
|
||||
for (auto& j : augmentations) {
|
||||
if (j.can_init()) {
|
||||
j.init(context);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = augmentations.rbegin(); it != augmentations.rend(); ++it) {
|
||||
if (it->can_finalize()) {
|
||||
it->finalize(context);
|
||||
}
|
||||
}
|
||||
|
||||
vector<worker_t> workers;
|
||||
|
||||
for (auto& j : augmentations) {
|
||||
if (j.can_start()) {
|
||||
workers.emplace_back(j.start(context));
|
||||
}
|
||||
}
|
||||
|
||||
augmentations_ = move(augmentations);
|
||||
workers_ = move(workers);
|
||||
}
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
application_t<M, Augmentations...>::
|
||||
~application_t() noexcept
|
||||
{
|
||||
try {
|
||||
join();
|
||||
}
|
||||
catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
void
|
||||
application_t<M, Augmentations...>::
|
||||
join()
|
||||
{
|
||||
for (auto& j : workers_) {
|
||||
j.join();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
template<typename... Args>
|
||||
vector<initializer_t>
|
||||
application_t<M, Augmentations...>::
|
||||
make_initializers(Args&&... args)
|
||||
{
|
||||
vector<initializer_t> initializers;
|
||||
|
||||
((
|
||||
initializers.emplace_back(std::in_place_type<factory_t<Augmentations>>)
|
||||
), ...);
|
||||
|
||||
initializers.emplace_back(
|
||||
std::in_place_type<factory_t<M, Args...>>,
|
||||
forward<Args>(args)...
|
||||
);
|
||||
|
||||
return initializers;
|
||||
}
|
||||
|
||||
template<typename M, typename... Augmentations>
|
||||
augmentation_t&
|
||||
application_t<M, Augmentations...>::
|
||||
do_find_augmentation(type_index type)
|
||||
{
|
||||
for (auto& j : augmentations_) {
|
||||
if (j.get_type() == type) {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
throw invalid_augmentation_t{};
|
||||
}
|
||||
|
||||
} // namespace code::build
|
72
code/build/buildfile
Normal file
72
code/build/buildfile
Normal file
@ -0,0 +1,72 @@
|
||||
intf_libs = # Interface dependencies.
|
||||
impl_libs = # Implementation dependencies.
|
||||
test_libs = # Test dependencies.
|
||||
|
||||
import intf_libs =+ libcode-uri%lib{code-uri}
|
||||
import intf_libs =+ libcode-json%lib{code-json}
|
||||
import intf_libs =+ libcode-seafire-common%lib{code-seafire-common}
|
||||
import intf_libs =+ libcode-seafire-protocol%lib{code-seafire-protocol}
|
||||
import intf_libs =+ libcode-seafire-server%lib{code-seafire-server}
|
||||
import intf_libs =+ libcode-seafire-routing%lib{code-seafire-routing}
|
||||
import intf_libs =+ libcode-seafire-representation%lib{code-seafire-representation}
|
||||
import intf_libs =+ libcode-seafire-resources%lib{code-seafire-resources}
|
||||
|
||||
./: lib{code-build}: libul{code-build}
|
||||
|
||||
libul{code-build}: {hxx ixx txx cxx}{** -**.test... -version} \
|
||||
{hxx }{ version}
|
||||
|
||||
libul{code-build}: $impl_libs $intf_libs
|
||||
|
||||
# Unit tests.
|
||||
#
|
||||
exe{*.test}:
|
||||
{
|
||||
test = true
|
||||
install = false
|
||||
}
|
||||
|
||||
for t: cxx{**.test...}
|
||||
{
|
||||
d = $directory($t)
|
||||
n = $name($t)...
|
||||
|
||||
./: $d/exe{$n}: $t $d/{hxx ixx txx}{+$n} $d/testscript{+$n} $test_libs
|
||||
$d/exe{$n}: libul{code-build}: bin.whole = false
|
||||
}
|
||||
|
||||
hxx{version}: in{version} $src_root/manifest
|
||||
{
|
||||
dist = true
|
||||
clean = ($src_root != $out_root)
|
||||
}
|
||||
|
||||
# Build options.
|
||||
#
|
||||
cxx.poptions =+ "-I$out_root" "-I$src_root"
|
||||
|
||||
# Export options.
|
||||
#
|
||||
lib{code-build}:
|
||||
{
|
||||
cxx.export.poptions = "-I$out_root" "-I$src_root"
|
||||
cxx.export.libs = $intf_libs
|
||||
}
|
||||
|
||||
# For pre-releases use the complete version to make sure they cannot
|
||||
# be used in place of another pre-release or the final version. See
|
||||
# the version module for details on the version.* variable values.
|
||||
#
|
||||
if $version.pre_release
|
||||
lib{code-build}: bin.lib.version = "-$version.project_id"
|
||||
else
|
||||
lib{code-build}: bin.lib.version = "-$version.major.$version.minor"
|
||||
|
||||
# Install into the code/build/ subdirectory of, say, /usr/include/
|
||||
# recreating subdirectories.
|
||||
#
|
||||
{hxx ixx txx}{*}:
|
||||
{
|
||||
install = include/code/build/
|
||||
install.subdirs = true
|
||||
}
|
244
code/build/diagnostics.cxx
Normal file
244
code/build/diagnostics.cxx
Normal file
@ -0,0 +1,244 @@
|
||||
#include <code/build/diagnostics.hxx>
|
||||
|
||||
#include <iomanip>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
static
|
||||
diagnostics_t*
|
||||
_activated{};
|
||||
|
||||
category_t::
|
||||
category_t(string prefix)
|
||||
: _prefix{move(prefix)}
|
||||
{}
|
||||
|
||||
string const&
|
||||
category_t::
|
||||
prefix() const
|
||||
{
|
||||
return _prefix;
|
||||
}
|
||||
|
||||
level_t::
|
||||
level_t(string prefix)
|
||||
: _prefix{move(prefix)}
|
||||
{}
|
||||
|
||||
string const&
|
||||
level_t::
|
||||
prefix() const
|
||||
{
|
||||
return _prefix;
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
activate()
|
||||
{
|
||||
_activated = this;
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
show_origin()
|
||||
{
|
||||
_show_origin = true;
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
hide_origin()
|
||||
{
|
||||
_show_origin = false;
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
enable(category_t const& category)
|
||||
{
|
||||
_categories.emplace(&category);
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
disable(category_t const& category)
|
||||
{
|
||||
_categories.erase(&category);
|
||||
}
|
||||
|
||||
bool
|
||||
diagnostics_t::
|
||||
is_enabled(category_t const& category)
|
||||
{
|
||||
return _categories.contains(&category);
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
enable(level_t const& level)
|
||||
{
|
||||
_severities.emplace(&level);
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
disable(level_t const& level)
|
||||
{
|
||||
_severities.erase(&level);
|
||||
}
|
||||
|
||||
bool
|
||||
diagnostics_t::
|
||||
is_enabled(level_t const& level)
|
||||
{
|
||||
return _severities.contains(&level);
|
||||
}
|
||||
|
||||
diagnostics_t::
|
||||
diagnostics_t() = default;
|
||||
|
||||
diagnostics_t::
|
||||
~diagnostics_t()
|
||||
{
|
||||
if (_activated == this) {
|
||||
_activated = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
string
|
||||
diagnostics_t::
|
||||
do_format(record_t const& record)
|
||||
{
|
||||
std::size_t c_length{0};
|
||||
|
||||
for (auto const& j : _categories) {
|
||||
if (j->prefix().size() > c_length) {
|
||||
c_length = j->prefix().size();
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t s_length{0};
|
||||
|
||||
for (auto const& j : _severities) {
|
||||
if (j->prefix().size() > s_length) {
|
||||
s_length = j->prefix().size();
|
||||
}
|
||||
}
|
||||
|
||||
stringstream what{record.what()};
|
||||
stringstream str;
|
||||
|
||||
for (string line; getline(what, line);) {
|
||||
str << std::setw(s_length) << std::left << record.level().prefix() << ": "
|
||||
<< std::setw(c_length) << std::left << record.category().prefix() << ": "
|
||||
<< line
|
||||
<< "\n"
|
||||
;
|
||||
}
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
void
|
||||
diagnostics_t::
|
||||
report(record_t const& record)
|
||||
{
|
||||
if (_activated) {
|
||||
if (
|
||||
_activated->is_enabled(record.category()) &&
|
||||
_activated->is_enabled(record.level())
|
||||
) {
|
||||
_activated->do_report(_activated->do_format(record));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
diagnostics_t::record_t::
|
||||
record_t(category_t const& category,
|
||||
level_t const& level,
|
||||
source_location const& origin)
|
||||
: _category{category},
|
||||
_level{level},
|
||||
_origin{origin}
|
||||
{}
|
||||
|
||||
diagnostics_t::record_t::
|
||||
~record_t() noexcept
|
||||
{
|
||||
diagnostics_t::report(*this);
|
||||
}
|
||||
|
||||
category_t const&
|
||||
diagnostics_t::record_t::
|
||||
category() const
|
||||
{
|
||||
return _category;
|
||||
}
|
||||
|
||||
level_t const&
|
||||
diagnostics_t::record_t::
|
||||
level() const
|
||||
{
|
||||
return _level;
|
||||
}
|
||||
|
||||
source_location const&
|
||||
diagnostics_t::record_t::
|
||||
origin() const
|
||||
{
|
||||
return _origin;
|
||||
}
|
||||
|
||||
string
|
||||
diagnostics_t::record_t::
|
||||
what() const
|
||||
{
|
||||
return _what.str();
|
||||
}
|
||||
|
||||
ostream_diagnostics_t::
|
||||
ostream_diagnostics_t(ostream& out)
|
||||
: _out{out}
|
||||
{}
|
||||
|
||||
void
|
||||
ostream_diagnostics_t::
|
||||
do_report(string const& what)
|
||||
{
|
||||
static mutex lock;
|
||||
|
||||
std::lock_guard<mutex> guard{lock};
|
||||
_out << what;
|
||||
}
|
||||
|
||||
level_t const&
|
||||
info()
|
||||
{
|
||||
static level_t level{"info"};
|
||||
return level;
|
||||
}
|
||||
|
||||
level_t const&
|
||||
warning()
|
||||
{
|
||||
static level_t level{"warning"};
|
||||
return level;
|
||||
}
|
||||
|
||||
level_t const&
|
||||
error()
|
||||
{
|
||||
static level_t level{"error"};
|
||||
return level;
|
||||
}
|
||||
|
||||
level_t const&
|
||||
debug()
|
||||
{
|
||||
static level_t level{"debug"};
|
||||
return level;
|
||||
}
|
||||
|
||||
} // namespace code::build
|
202
code/build/diagnostics.hxx
Normal file
202
code/build/diagnostics.hxx
Normal file
@ -0,0 +1,202 @@
|
||||
#ifndef code__build__diagnostics_hxx_
|
||||
#define code__build__diagnostics_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
class category_t
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
category_t(string);
|
||||
|
||||
category_t(category_t const&) = delete;
|
||||
category_t(category_t&&) = delete;
|
||||
|
||||
string const&
|
||||
prefix() const;
|
||||
|
||||
category_t& operator=(category_t const&) = delete;
|
||||
category_t& operator=(category_t&&) = delete;
|
||||
|
||||
private:
|
||||
string _prefix;
|
||||
|
||||
};
|
||||
|
||||
class level_t
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
level_t(string);
|
||||
|
||||
level_t(level_t const&) = delete;
|
||||
level_t(level_t&&) = delete;
|
||||
|
||||
string const&
|
||||
prefix() const;
|
||||
|
||||
level_t& operator=(level_t const&) = delete;
|
||||
level_t& operator=(level_t&&) = delete;
|
||||
|
||||
private:
|
||||
string _prefix;
|
||||
|
||||
};
|
||||
|
||||
class diagnostics_t
|
||||
{
|
||||
public:
|
||||
class record_t;
|
||||
friend record_t;
|
||||
|
||||
void
|
||||
activate();
|
||||
|
||||
void
|
||||
show_origin();
|
||||
|
||||
void
|
||||
hide_origin();
|
||||
|
||||
void
|
||||
enable(category_t const&);
|
||||
|
||||
void
|
||||
disable(category_t const&);
|
||||
|
||||
bool
|
||||
is_enabled(category_t const&);
|
||||
|
||||
void
|
||||
enable(level_t const&);
|
||||
|
||||
void
|
||||
disable(level_t const&);
|
||||
|
||||
bool
|
||||
is_enabled(level_t const&);
|
||||
|
||||
protected:
|
||||
diagnostics_t();
|
||||
|
||||
diagnostics_t(diagnostics_t const&) = delete;
|
||||
diagnostics_t(diagnostics_t&&) = delete;
|
||||
|
||||
~diagnostics_t() noexcept;
|
||||
|
||||
virtual
|
||||
string
|
||||
do_format(record_t const&);
|
||||
|
||||
virtual
|
||||
void
|
||||
do_report(string const&) = 0;
|
||||
|
||||
static
|
||||
void
|
||||
report(record_t const&);
|
||||
|
||||
private:
|
||||
bool _show_origin{};
|
||||
set<category_t const*> _categories;
|
||||
set<level_t const*> _severities;
|
||||
|
||||
};
|
||||
|
||||
class diagnostics_t::record_t
|
||||
{
|
||||
friend diagnostics_t;
|
||||
|
||||
public:
|
||||
record_t(category_t const&,
|
||||
level_t const&,
|
||||
source_location const& = source_location::current());
|
||||
|
||||
record_t(record_t const&) = delete;
|
||||
record_t(record_t&&) = delete;
|
||||
|
||||
~record_t() noexcept;
|
||||
|
||||
category_t const&
|
||||
category() const;
|
||||
|
||||
level_t const&
|
||||
level() const;
|
||||
|
||||
source_location const&
|
||||
origin() const;
|
||||
|
||||
string
|
||||
what() const;
|
||||
|
||||
record_t& operator=(record_t const&) = delete;
|
||||
record_t& operator=(record_t&&) = delete;
|
||||
|
||||
template<typename T>
|
||||
record_t&
|
||||
operator<<(T const& what)
|
||||
{
|
||||
_what << what;
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
category_t const& _category;
|
||||
level_t const& _level;
|
||||
source_location _origin;
|
||||
ostringstream _what;
|
||||
|
||||
};
|
||||
|
||||
inline
|
||||
diagnostics_t::record_t
|
||||
record(category_t const& category,
|
||||
level_t const& level,
|
||||
source_location const& = source_location::current())
|
||||
{
|
||||
return diagnostics_t::record_t{
|
||||
category,
|
||||
level
|
||||
};
|
||||
}
|
||||
|
||||
class ostream_diagnostics_t
|
||||
: public diagnostics_t
|
||||
{
|
||||
public:
|
||||
explicit
|
||||
ostream_diagnostics_t(ostream&);
|
||||
|
||||
ostream_diagnostics_t(ostream_diagnostics_t const&) = delete;
|
||||
ostream_diagnostics_t(ostream_diagnostics_t&&) = delete;
|
||||
|
||||
ostream_diagnostics_t& operator=(ostream_diagnostics_t const&) = delete;
|
||||
ostream_diagnostics_t& operator=(ostream_diagnostics_t&&) = delete;
|
||||
|
||||
protected:
|
||||
void
|
||||
do_report(string const&) override;
|
||||
|
||||
private:
|
||||
ostream& _out;
|
||||
|
||||
};
|
||||
|
||||
level_t const&
|
||||
info();
|
||||
|
||||
level_t const&
|
||||
warning();
|
||||
|
||||
level_t const&
|
||||
error();
|
||||
|
||||
level_t const&
|
||||
debug();
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#endif
|
58
code/build/except.hxx
Normal file
58
code/build/except.hxx
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef code__build__except_hxx_
|
||||
#define code__build__except_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
class not_implemented_t
|
||||
: public runtime_error
|
||||
{
|
||||
public:
|
||||
not_implemented_t(source_location origin = source_location::current())
|
||||
: runtime_error{"function not implemented"},
|
||||
_origin{move(origin)}
|
||||
{}
|
||||
|
||||
not_implemented_t(string what, source_location origin = source_location::current())
|
||||
: runtime_error{move(what)},
|
||||
_origin{move(origin)}
|
||||
{}
|
||||
|
||||
using runtime_error::runtime_error;
|
||||
|
||||
source_location const&
|
||||
origin() const
|
||||
{
|
||||
return _origin;
|
||||
}
|
||||
|
||||
private:
|
||||
source_location _origin;
|
||||
|
||||
};
|
||||
|
||||
class invalid_augmentation_t
|
||||
: public runtime_error
|
||||
{
|
||||
public:
|
||||
invalid_augmentation_t()
|
||||
: runtime_error{"invalid augmentation"}
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
class invalid_configurator_t
|
||||
: public runtime_error
|
||||
{
|
||||
public:
|
||||
invalid_configurator_t()
|
||||
: runtime_error{"invalid configurator"}
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#endif
|
67
code/build/initialization-context.hxx
Normal file
67
code/build/initialization-context.hxx
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef code__build__initialization_context_hxx_
|
||||
#define code__build__initialization_context_hxx_
|
||||
|
||||
#include <code/build/abstraction.hxx>
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
class initialization_context_t
|
||||
{
|
||||
public:
|
||||
template<typename A>
|
||||
A&
|
||||
find_augmentation()
|
||||
{
|
||||
return do_find_augmentation(typeid(A)).cast<A>();
|
||||
}
|
||||
|
||||
template<typename I, typename C, typename... Args>
|
||||
C&
|
||||
register_configurator(Args&&... args)
|
||||
{
|
||||
configurator_t c{
|
||||
std::in_place_type<I>,
|
||||
std::in_place_type<C>,
|
||||
forward<Args>(args)...
|
||||
};
|
||||
|
||||
return do_register_configurator(move(c)).cast<C>();
|
||||
}
|
||||
|
||||
template<typename C, typename I = C>
|
||||
C&
|
||||
find_configurator()
|
||||
{
|
||||
return do_find_configurator(typeid(I)).cast<C>();
|
||||
}
|
||||
|
||||
protected:
|
||||
initialization_context_t() = default;
|
||||
|
||||
~initialization_context_t() noexcept = default;
|
||||
|
||||
initialization_context_t(initialization_context_t const&) = delete;
|
||||
initialization_context_t(initialization_context_t&&) = delete;
|
||||
initialization_context_t& operator=(initialization_context_t const&) = delete;
|
||||
initialization_context_t& operator=(initialization_context_t&&) = delete;
|
||||
|
||||
private:
|
||||
virtual
|
||||
augmentation_t&
|
||||
do_find_augmentation(type_index) = 0;
|
||||
|
||||
virtual
|
||||
configurator_t&
|
||||
do_register_configurator(configurator_t) = 0;
|
||||
|
||||
virtual
|
||||
configurator_t&
|
||||
do_find_configurator(type_index) = 0;
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#endif
|
175
code/build/traits.hxx
Normal file
175
code/build/traits.hxx
Normal file
@ -0,0 +1,175 @@
|
||||
#ifndef code__build__traits_hxx_
|
||||
#define code__build__traits_hxx_
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
class initialization_context_t;
|
||||
class worker_t;
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
namespace code::build::traits
|
||||
{
|
||||
template<typename>
|
||||
struct function_traits;
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_traits<Ret(Args...)>
|
||||
{
|
||||
static constexpr std::size_t arity = sizeof...(Args);
|
||||
using return_type = std::decay_t<Ret>;
|
||||
using argument_tuple = std::tuple<std::decay_t<Args>...>;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
struct function_traits<Ret (Class::*)(Args...)>
|
||||
{
|
||||
static constexpr std::size_t arity = sizeof...(Args);
|
||||
using return_type = std::decay_t<Ret>;
|
||||
using class_type = Class;
|
||||
using argument_tuple = std::tuple<std::decay_t<Args>...>;
|
||||
};
|
||||
|
||||
template<typename Ret, typename Class, typename... Args>
|
||||
struct function_traits<Ret (Class::*)(Args...) const>
|
||||
{
|
||||
static constexpr std::size_t arity = sizeof...(Args);
|
||||
using return_type = std::decay_t<Ret>;
|
||||
using class_type = Class;
|
||||
using argument_tuple = std::tuple<std::decay_t<Args>...>;
|
||||
};
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
struct function_traits<Ret(*)(Args...)>
|
||||
{
|
||||
static constexpr std::size_t arity = sizeof...(Args);
|
||||
using return_type = std::decay_t<Ret>;
|
||||
using argument_tuple = std::tuple<std::decay_t<Args>...>;
|
||||
};
|
||||
|
||||
// function_arg_n
|
||||
//
|
||||
|
||||
template<
|
||||
typename F,
|
||||
std::size_t arg,
|
||||
std::size_t arity = function_traits<F>::arity
|
||||
>
|
||||
struct function_arg_n;
|
||||
|
||||
template<
|
||||
typename F,
|
||||
std::size_t arg
|
||||
>
|
||||
struct function_arg_n<F, arg, 1>
|
||||
{
|
||||
using function_traits = traits::function_traits<F>;
|
||||
using type = std::tuple_element_t<arg, typename function_traits::argument_tuple>;
|
||||
};
|
||||
|
||||
template<
|
||||
typename F,
|
||||
std::size_t arg
|
||||
>
|
||||
struct function_arg_n<F, arg, 2>
|
||||
{
|
||||
using function_traits = traits::function_traits<F>;
|
||||
using type = std::tuple_element_t<arg, typename function_traits::argument_tuple>;
|
||||
};
|
||||
|
||||
template<
|
||||
typename F,
|
||||
std::size_t arg
|
||||
>
|
||||
using function_arg_n_t = function_arg_n<F, arg>::type;
|
||||
|
||||
template<typename, typename = std::void_t<>>
|
||||
struct is_initializable_augmentation
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_initializable_augmentation<
|
||||
T,
|
||||
std::void_t<
|
||||
decltype(
|
||||
std::declval<T>().init(std::declval<initialization_context_t&>())
|
||||
)
|
||||
>
|
||||
> : std::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_initializable_augmentation_v{
|
||||
is_initializable_augmentation<T>::value
|
||||
};
|
||||
|
||||
template<typename, typename = std::void_t<>>
|
||||
struct is_finalizable_augmentation
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_finalizable_augmentation<
|
||||
T,
|
||||
std::void_t<
|
||||
decltype(
|
||||
std::declval<T>().finalize(std::declval<initialization_context_t&>())
|
||||
)
|
||||
>
|
||||
> : std::true_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_finalizable_augmentation_v{
|
||||
is_finalizable_augmentation<T>::value
|
||||
};
|
||||
|
||||
template<typename, typename = std::void_t<>>
|
||||
struct is_startable_augmentation
|
||||
: std::false_type
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
struct is_startable_augmentation<
|
||||
T,
|
||||
std::void_t<
|
||||
decltype(&T::start)
|
||||
>
|
||||
> : std::bool_constant<
|
||||
std::is_convertible_v<
|
||||
typename function_traits<decltype(&T::start)>::return_type,
|
||||
worker_t
|
||||
>
|
||||
>
|
||||
{};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr bool is_startable_augmentation_v{
|
||||
is_startable_augmentation<T>::value
|
||||
};
|
||||
|
||||
template<typename A>
|
||||
struct augmentation_traits
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
is_initializable{is_initializable_augmentation_v<A>};
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
is_finalizable{is_finalizable_augmentation_v<A>};
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
is_startable{is_startable_augmentation_v<A>};
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build::traits
|
||||
|
||||
#endif
|
99
code/build/types.hxx
Normal file
99
code/build/types.hxx
Normal file
@ -0,0 +1,99 @@
|
||||
#ifndef code__build__types_hxx_
|
||||
#define code__build__types_hxx_
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <source_location>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <thread>
|
||||
#include <typeindex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
using std::source_location;
|
||||
|
||||
using std::forward;
|
||||
using std::move;
|
||||
using std::swap;
|
||||
|
||||
using std::size_t;
|
||||
|
||||
using std::int8_t;
|
||||
using std::int16_t;
|
||||
using std::int32_t;
|
||||
using std::int64_t;
|
||||
using std::uint8_t;
|
||||
using std::uint16_t;
|
||||
using std::uint32_t;
|
||||
using std::uint64_t;
|
||||
|
||||
using std::function;
|
||||
|
||||
using std::istream;
|
||||
using std::ostream;
|
||||
using std::iostream;
|
||||
|
||||
using std::ifstream;
|
||||
using std::ofstream;
|
||||
using std::fstream;
|
||||
|
||||
using std::istringstream;
|
||||
using std::ostringstream;
|
||||
using std::stringstream;
|
||||
|
||||
using std::error_code;
|
||||
|
||||
using std::exception;
|
||||
using std::invalid_argument;
|
||||
using std::logic_error;
|
||||
using std::runtime_error;
|
||||
|
||||
using std::shared_ptr;
|
||||
using std::unique_ptr;
|
||||
|
||||
using std::make_shared;
|
||||
using std::make_unique;
|
||||
|
||||
using std::deque;
|
||||
using std::list;
|
||||
using std::map;
|
||||
using std::queue;
|
||||
using std::set;
|
||||
using std::tuple;
|
||||
using std::variant;
|
||||
using std::vector;
|
||||
|
||||
using std::optional;
|
||||
using std::nullopt;
|
||||
|
||||
using std::string;
|
||||
using strings = vector<string>;
|
||||
|
||||
using std::type_index;
|
||||
|
||||
using std::thread;
|
||||
using std::mutex;
|
||||
using std::recursive_mutex;
|
||||
|
||||
using std::chrono::system_clock;
|
||||
using time_point = system_clock::time_point;
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#endif
|
37
code/build/version.hxx.in
Normal file
37
code/build/version.hxx.in
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef code__build__version_hxx_
|
||||
#define code__build__version_hxx_
|
||||
|
||||
// The numeric version format is AAAAABBBBBCCCCCDDDE where:
|
||||
//
|
||||
// AAAAA - major version number
|
||||
// BBBBB - minor version number
|
||||
// CCCCC - bugfix version number
|
||||
// DDD - alpha / beta (DDD + 500) version number
|
||||
// E - final (0) / snapshot (1)
|
||||
//
|
||||
// When DDDE is not 0, 1 is subtracted from AAAAABBBBBCCCCC. For example:
|
||||
//
|
||||
// Version AAAAABBBBBCCCCCDDDE
|
||||
//
|
||||
// 0.1.0 0000000001000000000
|
||||
// 0.1.2 0000000001000020000
|
||||
// 1.2.3 0000100002000030000
|
||||
// 2.2.0-a.1 0000200001999990010
|
||||
// 3.0.0-b.2 0000299999999995020
|
||||
// 2.2.0-a.1.z 0000200001999990011
|
||||
//
|
||||
#define LIBCODE_BUILD_VERSION $libcode_build.version.project_number$ULL
|
||||
#define LIBCODE_BUILD_VERSION_STR "$libcode_build.version.project$"
|
||||
#define LIBCODE_BUILD_VERSION_ID "$libcode_build.version.project_id$"
|
||||
#define LIBCODE_BUILD_VERSION_FULL "$libcode_build.version$"
|
||||
|
||||
#define LIBCODE_BUILD_VERSION_MAJOR $libcode_build.version.major$
|
||||
#define LIBCODE_BUILD_VERSION_MINOR $libcode_build.version.minor$
|
||||
#define LIBCODE_BUILD_VERSION_PATCH $libcode_build.version.patch$
|
||||
|
||||
#define LIBCODE_BUILD_PRE_RELEASE $libcode_build.version.pre_release$
|
||||
|
||||
#define LIBCODE_BUILD_SNAPSHOT_SN $libcode_build.version.snapshot_sn$ULL
|
||||
#define LIBCODE_BUILD_SNAPSHOT_ID "$libcode_build.version.snapshot_id$"
|
||||
|
||||
#endif
|
38
code/build/visitor.hxx
Normal file
38
code/build/visitor.hxx
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef code__build__visitor_hxx_
|
||||
#define code__build__visitor_hxx_
|
||||
|
||||
namespace code::build
|
||||
{
|
||||
|
||||
class visitor_t
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
~visitor_t() noexcept = default;
|
||||
|
||||
virtual
|
||||
void
|
||||
visit_default() = 0;
|
||||
|
||||
protected:
|
||||
visitor_t() = default;
|
||||
|
||||
};
|
||||
|
||||
template<typename V>
|
||||
class basic_visitor_t
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
void
|
||||
visit(V const&) = 0;
|
||||
|
||||
protected:
|
||||
basic_visitor_t() = default;
|
||||
|
||||
~basic_visitor_t() noexcept = default;
|
||||
};
|
||||
|
||||
} // namespace code::build
|
||||
|
||||
#endif
|
105
code/build/web/augmentation.cxx
Normal file
105
code/build/web/augmentation.cxx
Normal file
@ -0,0 +1,105 @@
|
||||
#include <code/build/diagnostics.hxx>
|
||||
#include <code/build/version.hxx>
|
||||
|
||||
#include <code/build/web/augmentation.hxx>
|
||||
#include <code/build/web/configurator.hxx>
|
||||
#include <code/build/web/diagnostics.hxx>
|
||||
|
||||
#include <code/build/web/http-server.hxx>
|
||||
|
||||
#include <code/seafire/protocol/rfc7231/server.hxx>
|
||||
|
||||
#include <code/seafire/common/io/tcp-acceptor.hxx>
|
||||
#include <code/seafire/routing/router.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
augmentation_t::
|
||||
augmentation_t()
|
||||
: _diagnostics{std::cout} // fixme: make configurable
|
||||
{}
|
||||
|
||||
void
|
||||
augmentation_t::
|
||||
init(initialization_context_t& context)
|
||||
{
|
||||
record(web_category(), info()) << "initializing...";
|
||||
|
||||
auto& c = context.register_configurator<
|
||||
configurator_t,
|
||||
configurator_t
|
||||
>();
|
||||
|
||||
// provide some HTTP defaults for each response.
|
||||
//
|
||||
c.use(
|
||||
[]
|
||||
(
|
||||
seafire::server::request_t& req,
|
||||
seafire::server::response_t& res,
|
||||
seafire::server::request_handler_t const& next
|
||||
)
|
||||
{
|
||||
using code::seafire::protocol::rfc7231::server_t;
|
||||
using code::seafire::protocol::rfc7231::product_t;
|
||||
using code::seafire::protocol::rfc7231::products_t;
|
||||
|
||||
code::seafire::server::set<server_t>(res, products_t{
|
||||
product_t{"Code-Build", LIBCODE_BUILD_VERSION_STR}
|
||||
});
|
||||
|
||||
next.invoke(req, res);
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
worker_t
|
||||
augmentation_t::
|
||||
start(initialization_context_t& context)
|
||||
{
|
||||
auto& c = context.find_configurator<configurator_t>();
|
||||
|
||||
code::seafire::server::server_t::acceptor_set_t acceptors;
|
||||
|
||||
for (auto const& j : c.endpoints()) {
|
||||
acceptors.emplace(
|
||||
make_unique<code::seafire::common::io::tcp_acceptor_t>(_io_context, j)
|
||||
);
|
||||
}
|
||||
|
||||
if (acceptors.empty()) {
|
||||
record(
|
||||
web_category(),
|
||||
warning()
|
||||
) << "acceptor set empty, application will not accept any requests";
|
||||
}
|
||||
|
||||
record(web_category(), info()) << "routing table:\n" << c.root();
|
||||
|
||||
auto routing_table = c.build_routing_table();
|
||||
|
||||
{
|
||||
diagnostics_t::record_t r{web_category(), info()};
|
||||
|
||||
for (auto const& j : routing_table.endpoints()) {
|
||||
r << "configured endpoint: " << j << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
record(
|
||||
web_category(),
|
||||
info()
|
||||
) << "starting web server...";
|
||||
|
||||
return make_worker<http_server_t>(
|
||||
_io_context,
|
||||
_diagnostics,
|
||||
code::seafire::server::configuration_t{}, // fixme: make configurable.
|
||||
move(acceptors),
|
||||
code::seafire::routing::router_t{_diagnostics, routing_table}
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace code::build::web
|
40
code/build/web/augmentation.hxx
Normal file
40
code/build/web/augmentation.hxx
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef code__build__web__augmentation_hxx_
|
||||
#define code__build__web__augmentation_hxx_
|
||||
|
||||
#include <code/build/abstraction.hxx>
|
||||
#include <code/build/initialization-context.hxx>
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
#include <code/seafire/common/diagnostics.hxx>
|
||||
|
||||
#include <asio.hpp>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
class augmentation_t
|
||||
{
|
||||
public:
|
||||
augmentation_t();
|
||||
|
||||
augmentation_t(augmentation_t const&) = delete;
|
||||
augmentation_t(augmentation_t&&) = delete;
|
||||
|
||||
void
|
||||
init(initialization_context_t&);
|
||||
|
||||
worker_t
|
||||
start(initialization_context_t&);
|
||||
|
||||
augmentation_t& operator=(augmentation_t const&) = delete;
|
||||
augmentation_t& operator=(augmentation_t&&) = delete;
|
||||
|
||||
private:
|
||||
asio::io_context _io_context;
|
||||
seafire::common::ostream_diagnostics_t _diagnostics;
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build::web
|
||||
|
||||
#endif
|
62
code/build/web/configurator.cxx
Normal file
62
code/build/web/configurator.cxx
Normal file
@ -0,0 +1,62 @@
|
||||
#include <code/build/web/configurator.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
configurator_t::
|
||||
configurator_t() = default;
|
||||
|
||||
void
|
||||
configurator_t::
|
||||
add_endpoint(asio::ip::tcp::endpoint endpoint)
|
||||
{
|
||||
_endpoints.emplace_back(endpoint);
|
||||
}
|
||||
|
||||
seafire::routing::route_t&
|
||||
configurator_t::
|
||||
add_route()
|
||||
{
|
||||
return _root.add_route();
|
||||
}
|
||||
|
||||
seafire::routing::route_t&
|
||||
configurator_t::
|
||||
add_route(seafire::routing::route_t route)
|
||||
{
|
||||
return _root.add_route(move(route));
|
||||
}
|
||||
|
||||
void
|
||||
configurator_t::
|
||||
use(seafire::server::middleware_t middleware)
|
||||
{
|
||||
_root.use(move(middleware));
|
||||
}
|
||||
|
||||
vector<asio::ip::tcp::endpoint> const&
|
||||
configurator_t::
|
||||
endpoints() const
|
||||
{
|
||||
return _endpoints;
|
||||
}
|
||||
|
||||
seafire::routing::route_t const&
|
||||
configurator_t::
|
||||
root() const
|
||||
{
|
||||
return _root;
|
||||
}
|
||||
|
||||
seafire::routing::routing_table_t
|
||||
configurator_t::
|
||||
build_routing_table() const
|
||||
{
|
||||
seafire::routing::routing_table_t::builder_t builder;
|
||||
builder.add_route(root());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
} // namespace code::build::web
|
63
code/build/web/configurator.hxx
Normal file
63
code/build/web/configurator.hxx
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef code__build__web__configurator_hxx_
|
||||
#define code__build__web__configurator_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
#include <code/seafire/server/middleware.hxx>
|
||||
|
||||
#include <code/seafire/routing/route.hxx>
|
||||
#include <code/seafire/routing/routing-table.hxx>
|
||||
|
||||
#include <asio.hpp>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
class augmentation_t;
|
||||
|
||||
class configurator_t
|
||||
{
|
||||
friend augmentation_t;
|
||||
|
||||
public:
|
||||
class endpoint_t;
|
||||
|
||||
configurator_t();
|
||||
|
||||
configurator_t(configurator_t const&) = delete;
|
||||
configurator_t(configurator_t&&) = delete;
|
||||
|
||||
void
|
||||
add_endpoint(asio::ip::tcp::endpoint);
|
||||
|
||||
seafire::routing::route_t&
|
||||
add_route();
|
||||
|
||||
seafire::routing::route_t&
|
||||
add_route(seafire::routing::route_t);
|
||||
|
||||
void
|
||||
use(seafire::server::middleware_t);
|
||||
|
||||
configurator_t& operator=(configurator_t const&) = delete;
|
||||
configurator_t& operator=(configurator_t&&) = delete;
|
||||
|
||||
protected:
|
||||
vector<asio::ip::tcp::endpoint> const&
|
||||
endpoints() const;
|
||||
|
||||
seafire::routing::route_t const&
|
||||
root() const;
|
||||
|
||||
seafire::routing::routing_table_t
|
||||
build_routing_table() const;
|
||||
|
||||
private:
|
||||
vector<asio::ip::tcp::endpoint> _endpoints;
|
||||
seafire::routing::route_t _root;
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build::web
|
||||
|
||||
#endif
|
20
code/build/web/diagnostics.cxx
Normal file
20
code/build/web/diagnostics.cxx
Normal file
@ -0,0 +1,20 @@
|
||||
#include <code/build/web/diagnostics.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
category_t const&
|
||||
http_category()
|
||||
{
|
||||
static category_t const category{"http"};
|
||||
return category;
|
||||
}
|
||||
|
||||
category_t const&
|
||||
web_category()
|
||||
{
|
||||
static category_t const category{"web"};
|
||||
return category;
|
||||
}
|
||||
|
||||
} // namespace code::build::web
|
18
code/build/web/diagnostics.hxx
Normal file
18
code/build/web/diagnostics.hxx
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef code__build__web__diagnostics_hxx_
|
||||
#define code__build__web__diagnostics_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
#include <code/build/diagnostics.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
category_t const&
|
||||
http_category();
|
||||
|
||||
category_t const&
|
||||
web_category();
|
||||
|
||||
} // namespace code::build::web
|
||||
|
||||
#endif
|
19
code/build/web/except.cxx
Normal file
19
code/build/web/except.cxx
Normal file
@ -0,0 +1,19 @@
|
||||
#include <code/build/web/except.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
web_exception_t::
|
||||
web_exception_t(seafire::server::common_error_t error, string what)
|
||||
: runtime_error{move(what)},
|
||||
_error{error}
|
||||
{}
|
||||
|
||||
seafire::server::common_error_t
|
||||
web_exception_t::
|
||||
error() const
|
||||
{
|
||||
return _error;
|
||||
}
|
||||
|
||||
} // namespace code::build::web
|
28
code/build/web/except.hxx
Normal file
28
code/build/web/except.hxx
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef code__build__web__except_hxx_
|
||||
#define code__build__web__except_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
#include <code/seafire/server/common-error.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
class web_exception_t
|
||||
: public runtime_error
|
||||
{
|
||||
public:
|
||||
web_exception_t(seafire::server::common_error_t, string);
|
||||
|
||||
seafire::server::common_error_t
|
||||
error() const;
|
||||
|
||||
private:
|
||||
seafire::server::common_error_t _error;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build::web
|
||||
|
||||
#endif
|
85
code/build/web/http-server.cxx
Normal file
85
code/build/web/http-server.cxx
Normal file
@ -0,0 +1,85 @@
|
||||
#include <code/build/web/http-server.hxx>
|
||||
#include <code/build/web/diagnostics.hxx>
|
||||
#include <code/build/web/except.hxx>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
http_server_t::
|
||||
http_server_t(asio::io_context& io_context,
|
||||
seafire::common::diagnostics_t& d,
|
||||
seafire::server::configuration_t config,
|
||||
seafire::server::server_t::acceptor_set_t acceptors,
|
||||
seafire::server::request_handler_t handler)
|
||||
: seafire::server::server_t{d, config, move(acceptors), handler},
|
||||
_io_context{io_context}
|
||||
{
|
||||
start();
|
||||
|
||||
for (int i; i < 8; ++i) {
|
||||
_threads.emplace_back([this] { run(); });
|
||||
}
|
||||
}
|
||||
|
||||
http_server_t::
|
||||
~http_server_t() noexcept = default;
|
||||
|
||||
void
|
||||
http_server_t::
|
||||
join()
|
||||
{
|
||||
for (auto& j : _threads) {
|
||||
j.join();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
http_server_t::
|
||||
on_error(seafire::server::request_t& req,
|
||||
seafire::server::response_t& res,
|
||||
seafire::server::common_error_t error)
|
||||
{
|
||||
seafire::server::server_t::on_error(req, res, error);
|
||||
}
|
||||
|
||||
void
|
||||
http_server_t::
|
||||
on_exception(seafire::server::request_t&,
|
||||
seafire::server::response_t& res) noexcept
|
||||
{
|
||||
try {
|
||||
throw;
|
||||
}
|
||||
catch (web_exception_t const& ex) {
|
||||
record(
|
||||
web_category(),
|
||||
error()
|
||||
) << "exception: " << ex.what() << ": " << (int)ex.error();
|
||||
|
||||
res.send(ex.error());
|
||||
return;
|
||||
}
|
||||
catch (exception const& ex) {
|
||||
record(
|
||||
web_category(),
|
||||
error()
|
||||
) << "exception: " << ex.what();
|
||||
}
|
||||
// catch (...) {
|
||||
// record(
|
||||
// web_category(),
|
||||
// error()
|
||||
// ) << "exception: unknown exception thrown";
|
||||
// }
|
||||
|
||||
res.send(500);
|
||||
}
|
||||
|
||||
void
|
||||
http_server_t::
|
||||
run()
|
||||
{
|
||||
_io_context.run();
|
||||
}
|
||||
|
||||
} // namespace code::build::web
|
55
code/build/web/http-server.hxx
Normal file
55
code/build/web/http-server.hxx
Normal file
@ -0,0 +1,55 @@
|
||||
#ifndef code__build__web__http_server_hxx_
|
||||
#define code__build__web__http_server_hxx_
|
||||
|
||||
#include <code/build/types.hxx>
|
||||
|
||||
#include <code/seafire/common/diagnostics.hxx>
|
||||
|
||||
#include <code/seafire/server/configuration.hxx>
|
||||
#include <code/seafire/server/request-handler.hxx>
|
||||
#include <code/seafire/server/request.hxx>
|
||||
#include <code/seafire/server/response.hxx>
|
||||
#include <code/seafire/server/server.hxx>
|
||||
|
||||
#include <asio.hpp>
|
||||
|
||||
namespace code::build::web
|
||||
{
|
||||
|
||||
class http_server_t
|
||||
: seafire::server::server_t
|
||||
{
|
||||
public:
|
||||
http_server_t(asio::io_context&,
|
||||
seafire::common::diagnostics_t&,
|
||||
seafire::server::configuration_t,
|
||||
seafire::server::server_t::acceptor_set_t,
|
||||
seafire::server::request_handler_t);
|
||||
|
||||
~http_server_t() noexcept;
|
||||
|
||||
void
|
||||
join();
|
||||
|
||||
protected:
|
||||
void
|
||||
on_error(seafire::server::request_t&,
|
||||
seafire::server::response_t&,
|
||||
seafire::server::common_error_t) override;
|
||||
|
||||
void
|
||||
on_exception(seafire::server::request_t&,
|
||||
seafire::server::response_t&) noexcept override;
|
||||
|
||||
private:
|
||||
void
|
||||
run();
|
||||
|
||||
asio::io_context& _io_context;
|
||||
vector<thread> _threads;
|
||||
|
||||
};
|
||||
|
||||
} // namespace code::build::web
|
||||
|
||||
#endif
|
20
manifest
Normal file
20
manifest
Normal file
@ -0,0 +1,20 @@
|
||||
: 1
|
||||
name: libcode-build
|
||||
version: 0.1.0-a.0.z
|
||||
language: c++
|
||||
summary: libcode-build C++ library
|
||||
license: BSD-4-Clause
|
||||
description-file: README.md
|
||||
url: https://helloryan.se/code/
|
||||
email: ryan@helloryan.se
|
||||
depends: * build2 >= 0.17.0
|
||||
depends: * bpkg >= 0.17.0
|
||||
depends: libasio ^1.29.0
|
||||
depends: libcode-uri ^0.1.0-
|
||||
depends: libcode-json ^0.1.0-
|
||||
depends: libcode-seafire-common ^0.1.0-
|
||||
depends: libcode-seafire-protocol ^0.1.0-
|
||||
depends: libcode-seafire-server ^0.1.0-
|
||||
depends: libcode-seafire-routing ^0.1.0-
|
||||
depends: libcode-seafire-representation ^0.1.0-
|
||||
depends: libcode-seafire-resources ^0.1.0-
|
39
repositories.manifest
Normal file
39
repositories.manifest
Normal file
@ -0,0 +1,39 @@
|
||||
: 1
|
||||
summary: libcode-build project repository
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://pkg.cppget.org/1/beta
|
||||
trust: 70:64:FE:E4:E0:F3:60:F1:B4:51:E1:FA:12:5C:E0:B3:DB:DF:96:33:39:B9:2E:E5:C2:68:63:4C:A6:47:39:43
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-uri.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-json.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-seafire-common.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-seafire-protocol.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-seafire-server.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-seafire-routing.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-seafire-representation.git##HEAD
|
||||
|
||||
:
|
||||
role: prerequisite
|
||||
location: https://code.helloryan.se/code/libcode-seafire-resources.git##HEAD
|
8
tests/.gitignore
vendored
Normal file
8
tests/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Test executables.
|
||||
#
|
||||
driver
|
||||
|
||||
# Testscript output directories (can be symlinks).
|
||||
#
|
||||
test
|
||||
test-*
|
4
tests/build/.gitignore
vendored
Normal file
4
tests/build/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
/config.build
|
||||
/root/
|
||||
/bootstrap/
|
||||
build/
|
5
tests/build/bootstrap.build
Normal file
5
tests/build/bootstrap.build
Normal file
@ -0,0 +1,5 @@
|
||||
project = # Unnamed tests subproject.
|
||||
|
||||
using config
|
||||
using test
|
||||
using dist
|
16
tests/build/root.build
Normal file
16
tests/build/root.build
Normal file
@ -0,0 +1,16 @@
|
||||
cxx.std = latest
|
||||
|
||||
using cxx
|
||||
|
||||
hxx{*}: extension = hxx
|
||||
ixx{*}: extension = ixx
|
||||
txx{*}: extension = txx
|
||||
cxx{*}: extension = cxx
|
||||
|
||||
# Every exe{} in this subproject is by default a test.
|
||||
#
|
||||
exe{*}: test = true
|
||||
|
||||
# The test target for cross-testing (running tests under Wine, etc).
|
||||
#
|
||||
test.target = $cxx.target
|
1
tests/buildfile
Normal file
1
tests/buildfile
Normal file
@ -0,0 +1 @@
|
||||
./: {*/ -build/}
|
Loading…
x
Reference in New Issue
Block a user