CHANGELOG.md
Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
Added
Build system
- All executable and library targets now receive preprocessor definitions describing the target they're being compiled for
- On Unix-like systems, the symbol
CRUCIBLE_UNIX
is defined in all header and source files - On Windows-like systems, the symbol
CRUCIBLE_WINDOWS
is defined in all header and source files - On all targets, the symbol
CRUCIBLE_ROOT
is defined to the path to the root of the repository
- On Unix-like systems, the symbol
core
library
- A library-level
core.hpp
header that#include
s all othercore
headers - A new namespace called
fallible
- Provides a very similar type to
either::Either
, but with better semantics and more specific names - Also provides analogues for
either::Lhs
andeither::Rhs
calledfallible::Failure
andfallible::Success
- Also also provides a type called
Error
that serves as a variadic error type container
- Provides a very similar type to
- A new namespace called
arrays
- Provides two new types:
Array
, which owns a dynamically allocated buffer; andSlice
, which views a subsection of anArray
- Also provides two overloads of a function called
make_array()
, which constructs anArray
from a C array of static or dynamic size
- Provides two new types:
- A new overload of
format::format_carray()
that accepts asize
argument - A new API for formatting classes and structs:
format_record()
andbuild_fields()
- A new type,
format::Context
, supplies formatting parameters and can be made withformat::build_context()
format_record()
is a utility function that is called fromT::format()
for anyT
build_fields()
is used to obtain a builder object that collects all of the fields in the object into a string
- A new type,
- A new API for working with packed bit arrays called
bitarray
- A class called
BitArray
that owns its storage - Another class called
BitSlice
that borrows a range of storage from aBitArray
- A class called
- A new API for typed memory buffers called
buffer
, containing:- A template class called
Buffer
that holds a pointer and a size (and auto-frees the pointer on destruction) - Free functions
make_buffer_by_copy()
andmake_buffer_by_move()
for creating aBuffer
from a pointer and size
- A template class called
array
,bit_array
, andbuffer
can now all be constructed using astd::initializer_list
array
andbit_array
can now be constructed using a C-style array (andbuffer
always could be)make_buffer_by_move()
changed to do an element-wise move rather than steal a pointerbuffer::Accumulator
added to handle building up aBuffer
procedurally rather than using astd::vector
or raw array- A formatter for
std::variant
grok
library
- A new library that will (eventually) replace the
parsing
library
meta
library
- A new library for communicating meta-level information (like libc capabilities) from the build system to the source code
- Runtime capabilities (mainly of the C library) can be checked using the
CRUCIBLE_META_CAPABILITY_*
macros in thecapability.hpp
header
process
library
- This is a new library that deals with things related to the process that Crucible is running inside of
- So far, there is one namespace called
backtrace
, which deals with getting backtraces in a cross-platform way:- The
take_detailed_snapshot()
function captures as much debug information as possible inDetailedStackFrame
objects - The
take_simple_snapshot()
function captures only function names inSimpleStackFrame
objects - The
terminate_handler()
function can be registered as a terminate handler usingstd::set_terminate()
to print a nice crash report
- The
- There is also the usual
result
namespace, with two error types so far:EmptyBacktrace
indicates that the stack walking mechanism found 0 frames above the caller in the current thread's call stackMissingDebugInformation
indicates that a detailed snapshot couldn't be performed because there was no debug information found
testing
library
- A library-level
testing.hpp
header that#include
s all othertesting
headers - Two new macros:
EXPECT_FAILURE()
andEXPECT_SUCCESS()
, which test the state of afallible::Result
object
unix
library
- A library-level
unix.hpp
header that#include
s all otherunix
headers - A new namespace called
backtrace
- Provides a function called
snapshot()
which takes a snapshot of the current call stack - Also provides a simple type called
Frame
which holds the symbol associated with each frame of the call stack
- Provides a function called
windows
library
- A library-level
windows.hpp
header that#incude
s all otherwindows
headers - A new namespace called
backtrace
- Provides a function called
snapshot()
which takes a snapshot of the current call stack - Also provides a simple type called
Frame
which holds a semantic description of one frame of the call stack
- Provides a function called
Changed
General
- Combined the
boba
library with thevm
library, then renamed it tobolt
- Changed the supported Linux variant from Arch on amd64 to Ubuntu on amd64 in the README
- Clarified the supported versions of macOS and Windows in the README
- Convert all uses of
core::either
to usecore::fallible
instead- Exception:
parsing
still usescore::either
, because it needs more work to support the change
- Exception:
- All macro names across all targets have been standardized to the same naming convention
Build system
- Unified naming of all CMake modules, functions, and variables to make it obvious when something is part of Crucible
- Modules are named with the convention
CrucibleXyz.cmake
- Functions are named with the convention
crucible_xyz()
- Variables are named with the convention
CRUCIBLE_XYZ
- Modules are named with the convention
- Hid some low-level cache variables behind new CMake functions
crucible_configure_language_standards()
handles setting language flagscrucible_configure_output_directory()
handles setting the output directory of final artifactscrucible_configure_shared_library_exports()
handles setting flags for how shared library exports are handled
- Handle platform-specific libraries in the
CMakeLists.txt
for those libraries
core
library
- All
format
functions now takeT const &
instead ofT &&
, because formatters should never change the thing they're formatting arrays::Array
andarrays::Slice
now use the new formatting APIcore::assert
has better formatting for its messages nowformat::format_pointer()
now requires a formatting context so it can render a pointed-to record properlyfallible::Failure
,fallible::Success
, andfallible::Result
now behave more like a true sum type (and by extension, functor and monad)- Renamed
core::fallible
tocore::result
- Renamed
core::bitarray
tocore::bit_array
array::Array
andbit_array::BitArray
are now backed bybuffer::Buffer
instead of raw memory
testing
library
testing::cli::execute()
now sets the terminate handler toprocess::backtrace::terminate_handler()
, which prints a crash reporttesting::expect
has better formatting for its messages nowtesting::console_reporter
has totally redone reporting for better readability- Failures are now collected and displayed at the end, rather than printed inline with the tests
- Instead of indenting to show hierarchy, section headers with underlining and colors are used to flatten the output and make it easier to read
Deprecated
Removed
- The
bobadump
executable is totally gone, becauseboba
has been rolled into thebolt
library - The
os
library is gone, because its only user wasbobadump
(which was also removed) - The
core::resource_warden
namespace is gone, because it's very easy to get the same functionality without it - The
parsing
library is removed and will be replaced withgrok
- The
bolt
library was emptied out and will be remade oncegrok
is ready
Fixed
- Check the target compatibility after setting the C++ standard (so that
static_assert
works properly) - Make sure to save the
CMAKE_*_OUTPUT_DIRECTORY
variables to the CMake cache - Fixed compilation errors and failing tests when building on Linux
core::fallible::Result::bind_failure()
andcore::fallible::Result::bind_success()
now perform a real>>=
operation- Bug in the macro expansion of
ASSERT()
which made it not compile (comparisons were unaffected)
Security
0.6.0
Released on February 05, 2022.
Added
parsing
library
- A new combinator called
Map
and associated factory functionmake_map()
- Accepts a parser and a function and transforms the result of the parser using the function
- A new combinator called
Bind
and associated factory functionmake_bind()
- Uses the result of one parser to build a new parser, then applies the new parser
- A new combinator called
Tee
and associated factory functionmake_tee()
- Similar to
Bind
, but keeps the output of both parsers and returns it in astd::pair
- Similar to
- Several new factory functions and types in the
bytes
namespace (used to be thebits
namespace):Endianness
, an enumeration used to distinguish big-endian and little-endian parsers from one anotherU8Le
,U16Le
,U32Le
,U64Be
,U8Be
,U16Be
,U32Be
, andU64Be
: parsers for the appropriate type and endiannessmake_exact()
andmake_take()
: factory functions for creatingExact
andTake
parsersmake_u8_le()
,make_u16_le()
,make_u32_le()
,make_u64_le()
: factory functions for little-endian unsigned integer parsersmake_u8_be()
,make_u16_be()
,make_u32_be()
,make_u64_be()
: factory functions for big-endian unsigned integer parsers
Changed
Build system
- Disabled the
C4180
compiler warning on MSVC due to not being helpful and causing the build to fail
bobadump
executable
- Updated output to correspond with new Boba format
boba
library
- Total overhaul of the file format and internals
- The schema block is gone; instead we have a special container metadata section
- The
from_bytes()
API is exactly the same, but theContainer
type is now a simple record containing a vector of headers
- New namespace:
container
- Contains simple record types for both individual block headers and the container as a whole
- New namespace:
read
- The
from_bytes()
function was moved here
- The
parsing
library
- The meaning of the
Into
parser combinator has changedInto<T>
now converts the result of its wrapped parser into aT
using one ofT
's constructors
- The
bits
namespace has been renamed tobytes
, and also renamed the contents:- Renamed
BitsState
type toState
- Renamed
ByteSequence
parser toExact
- Renamed
SizedByteSequence
parser toTake
- Combined
BigEndianUnsignedInteger
andLittleEndianUnsignedInteger
parsers intoUnsignedInteger
- Renamed
Removed
boba
library
- The
metadata
namespace is gone; see the newcontainer
andread
namespaces for equivalent functionality
parsing
library
- The
>>
operator is no longer overloaded to construct an instance ofInto
- Use
make_into()
instead
- Use
Fixed
bobadump
executable
- Tests were not passing on windows due to
\r\n
line endings not being handled correctly in the test script
parsing
library
- Compilation errors on macOS due to mis-ordered class fields and missing constructors
0.5.0
Released on January 01, 2022.
Added
bobadump
executable
- New executable for dumping Boba files
- No options; just use
crucible-bobadump BOBA_FILE
- Prints the schema header (but not the schema entries) and each user header
- No options; just use
core
library
- New formatter for primitive integer types called
format_integral()
- Will work on anything for which
std::is_integral
evaluates totrue
- Will work on anything for which
- New abstract method in
AbstractError
calleddescribe()
- In contrast to
format()
, which is intended for developers,describe()
is intended for end users
- In contrast to
either::Either
got new methodsbind_lhs()
andbind_rhs()
- Maps a value to a whole new
Either
instance - This is in contrast to
map_lhs()
andmap_rhs()
, which map a value to another value - Can be used to chain
Either
-returning functions together
- Maps a value to a whole new
os
library
- New library for abstracting over "operating-system-y" things
- Automatically switches between
unix
andwindows
as a backend depending on the compilation target - The
fs
namespace has platform-agnostic wrapper functions for all of the utilities inunix::fs
andwindows::fs
- Automatically switches between
Build system
- Support for Python test drivers via
add_crucible_python_test()
(intended mainly for testing executables)
General
- Added information about Python tests to the readme
- Added information about supported compilation targets to the readme
Changed
bobadump
executable
- Renamed from
boba-dump
to justbobadump
core
library
either::LHS
andeither::RHS
renamed toeither::Lhs
andeither::Rhs
for readability
os
library
- The Windows implementation of the
fs
namespace now uses thebind_lhs()
andbind_rhs()
APIs ofcore::either::Either
Build system
- Silenced the message from
find_package
, which could be really long and was basically just noise
General
- All uses of
Result
have been changed toEither
to remove duplicated code - Better end-user error messages across the board
- Uses of "Boba" as a word standardized on camel-case, not uppercase (
BOBA
) or lowercase (boba
)
Removed
- The
core::result
namespace has been completely removed; usecore::either
instead
Fixed
parsing
library
- Compilation error on MSVC due to signed/unsigned comparison mismatch
unix
library
- Errors now have their details reported properly (we see the
errno
message)
windows
library
- Errors now have their details reported properly (we see the
GetLastError()
message)
0.4.0
Released on December 04, 2021.
Added
New libraries
boba
, the reference implementation of the BOBA (Bunch Of Big Arrays) file format
boba
library
- The new
errors
namespace:- The main error class
BobaError
- The
ParsingFailed
error variant for when loading a BOBA container fails - A type alias
BobaResult
forcore::result::Result
- The main error class
- The new
metadata
namespace:- A POD type called
Header
for keeping the (almost) raw information about each block header - A type called
Schema
that wraps the very firstHeader
of a container, providing information about the rest of the contents - A type called
Container
that holds all block headers and provides iterator access to them, as well as the schema - A function called
from_bytes()
which deserializes a byte stream into aContainer
- A POD type called
core
library
- The
format
namespace:- Lots of functions for formatting anything you can think of: STL containers, plain arrays, C strings, pointers...
- A
format_anything()
function which intelligently selects a formatter based on a compile-time type check
- Lots of new
ASSERT
macros, for parity with theEXPECT
API - The
errors
namespace:- An abstract base class called
AbstractError
, intended to be used for theFailure
alternative ofResult
instances
- An abstract base class called
- Support for
std::tuple
informat::format_anything()
constexpr
comparison operators fornone::None
parsing
library
- A new combinator called
SequenceOf
- Used to parse an exact number of repetitions of a single structure
- Fails if there aren't enough occurrences (but it's fine to have more)
- Has an associated error called
SequenceOfError
- The
errors
namespace:- Error variants
AmbiguousMatch
,UnexpectedInput
, andUnexpectedEndOfInput
- The main error class
ParsingError
and aResult
alias namedParsingResult
- Error variants
- A new combinator called
Tuple
- Used to parse a heterogeneous sequence of substructures
- No combinator operator; use
combinators::make_tuple()
- New factory functions for each combinator:
make_one_of()
,make_pair()
,make_into()
, andmake_sequence_of()
unix
library
- The
errors
namespace:- The
HostError
type, which is moved from the olderrno_error::ErrnoError
type - Error variants moved from the
fs
namespace - The main error class
UnixError
and aResult
alias namedUnixError
- The
windows
library
- The
errors
namespace:- The
HostError
, which is moved from the oldwindows_error::WindowsError
type - Error variants moved from the
fs
andtranscoding
namespaces - The main error class
WindowsError
and aResult
alias namedWindowsResult
- The
testing
library
- Self tests (at least, for the parts that can be isolated and tested!)
Changed
ASSERT
,EXPECT
, andResult
now use theformat_anything()
function to render objects- All error handling is now done using a combination of
core::errors::AbstractError
andcore::result::Result
- Each library now has an
errors
namespace in which it defines its own specializations of these types
- Each library now has an
core
library
none::None
now formats as"None"
instead of"None {}"
parsing
library
AndThen
combinator renamed toPair
(as a special case ofTuple
)
Removed
ASSERT_NOT_NULL
is gone; useASSERT_NE(thing, nullptr)
- The
parsing::result
,unix::errno_error
, andwindows::windows_error
namespaces are all gone- See the
errors
namespaces in each library for a standardized replacement
- See the
0.3.0
Released on November 06, 2021.
Added
core
library
- A new namespace called
assert
, containing functions for implementing theASSERT
macro family - In the
assert
namespace:- A pair of new macros called
ASSERT
andASSERT_NOT_NULL
, which terminate the program with a message if the assertion does not pass - A template function called
fail
, which implements the assertion failure mechanism
- A pair of new macros called
- A new namespace called
either
, containing theEither
type for holding one of two types of value - In the
either
namespace:- A tag type called
PreventSelectionForCopyAndMove
used internally - A pair of templates called
LHS
andRHS
which distinguish the alternatives of anEither
- A template called
Either
which can hold one of two values, which can have different types - A pair of functions called
make_lhs()
andmake_rhs()
, which can be used to createLHS
andRHS
instances to pass to anEither
- A tag type called
parsing
library
- In the
bits
namespace:- A new parser called
SizedByteSequence
which extracts a specific number of bytes from the input
- A new parser called
- In the
combinators
namespace:- A new combinator called
Into
, which functions likeAndThen
but dynamically constructs the second parser based on the result of the first parser - Two new errors called
AndThenError
andIntoError
, which serve as error types for theAndThen
andInto
combinators
- A new combinator called
- In the
combinators::operators
namespace:- An overloaded
>>
operator, which buildsInto
instances from a parser and a function
- An overloaded
testing
library
- In the
expect
namespace:- A pair of new macros called
EXPECT_CONTAINER_EQ
andEXPECT_CONTAINER_NE
, which check for (in)equality between two iterables
- A pair of new macros called
- In the
abstract_reporter
namespace:- The
AbstractReporter
class now has default do-nothing implementations for all of its virtual methods - Two new hook methods for
AbstractReporter
:handle_group_start()
andhandle_group_end()
, which get the name of the group
- The
- In the
reporter
namespace:- Forwarding methods for the
handle_group_start()
andhandle_group_end()
hooks
- Forwarding methods for the
- In the
console_reporter
namespace:- An implementation of
handle_group_start
that prints the group name
- An implementation of
Changed
testing
library
- Scenarios and fixtures now both accept a tag argument before the name, which groups the fixtures and scenarios together
- Tags can be filtered on the command line with the
-t
or--tag
option - Fixtures will only be run for the scenarios that have the same tag
BeforeAll
andAfterAll
fixtures will only run if their tag isn't being filtered out
- Tags can be filtered on the command line with the
- Output rendering is much clearer
- A count of total scenarios run is now printed
- Fixtures are now printed at the same level as scenarios instead of inside them
- Fixtures receive a pass/fail note (when they would be printed anyways)
- Added icons for each keyword to make distinguishing them a little clearer
- Removed all white and bright white to make reading output on a white background easier
- "Tags" renamed to "Groups"
- The option in the CLI runner has been changed from
-t/--tag
to-g/--group
- The option in the CLI runner has been changed from
- Groups are now used as "containers" for scenarios
- There are now two loops: one over each group, and another over each scenario within the group
BeforeAll
andAfterAll
fixtures now run only within their group, not at the start or end of the whole suite- The console reporter will show groups as the main heading now, with scenarios and fixtures underneath
unix
library
test_fs
now uses the fixture mechanism to create and delete its file structure
General
- Turned all instances of
std::u8string
,std::u8string_view
,char8_t
, andu8""
literals back into their legacy versions due to bad support - Standardized constructor syntax (
{}
unless()
is semantically required)
parsing
library
- The
bits::ByteSequence
andtext::CharacterSequence
parsers now make a deep copy of their sequences - The
bits::ByteSequence
parser has been renamed tobits::ExactByteSequence
Fixed
- Compilation error on AppleClang:
no viable constructor or deduction guide
incore::assert::fail()
0.2.0
Released on October 02, 2021.
Added
New libraries
vm
library for the virtual machine implementationparsing
library for parser combinators
parsing
library features
bits
namespace containing primitives for parsing binary dataFixedWidthUnsignedIntegerType
concept, which constrains to one of thestd::uintN_t
typesByteSequenceMismatch
basic error typeUnexpectedEndOfInput
basic error typeBitsError
composite error typeBitsState
type specialized for binary dataByteSequence
parser which matches an exact sequence of bytesLittleEndianUnsignedInteger
parser templateBigEndianUnsignedInteger
parser template
combinators
namespace containing types for combining simple parsers into more complex parsersBothMatch
error templateNeitherMatch
error templateOneOfError
composite error typeOneOf
parser combinator, which matches exclusively one or the other of the child parsersAndThen
parser combinator, which matches one parser followed by another parser and returns both resultsoperators
namespace containing tools for building combinator treesoperator^
, which combines two parsers using theOneOf
combinatoroperator&
, which combines two parsers using theAndThen
combinator
result
namespace containing utility types for the outcomes of individual parsersReject
template for holding information about a rejected parseAccept
template for holding information about an accepted parsereject
function for building aReject
wrapped in acore::result::Failure
accept
function for building anAccept
wrapped in acore::result::Success
text
namespace containing primitives for parsing UTF-8 dataCharacterSequenceMismatch
basic error typeTextError
composite error typeTextState
type specialized for UTF-8 dataCharacterSequence
parser which matches an exact sequence of characters
testing
library features
- New namespace:
fixture
for types related to test fixtures - In the
fixture
namespace:FixtureFunction
alias for the type of a fixture functionFixtureVariant
template type which serves as a base class for each kind of fixtureBeforeAll
,AfterAll
,BeforeEach
, andAfterEach
tag types which differentiate each kind of fixture- The
Fixture
type itself, which abstracts over all of these details - In the
FixtureVariant
type:- A constructor accepting a
FixtureFunction
- A getter method called
get_name()
which returns the name of the fixture variant based on which derived class calls it - A method named
execute()
which runs the fixture and returns an outcome, just like a scenario
- A constructor accepting a
- In the
BeforeAll
,AfterAll
,BeforeEach
, andAfterEach
types:- A constant string field containing the name of the variant for reporting purposes
- In the
Fixture
type:- A constructor which accepts a name and a fixture variant
- A template method called
has_variant()
which checks what kind of fixture this is - A method called
get_variant_name()
which forwards toget_name()
on the underlying variant - A getter method called
get_name()
which retrieves the fixture's name - A method called
execute()
which forwards toexecute()
on the underlying variant
- In the
suite
namespace:- Four new macros which define fixtures in the same way as scenarios:
BEFORE_ALL
,AFTER_ALL
,BEFORE_EACH
, andAFTER_EACH
- A new type called
FixtureRegistrar
which is used by the new macros to add fixtures to the suite - In the
FixtureRegistrar
type:- A constructor that forwards to
add_fixture()
on the suite
- A constructor that forwards to
- In the
Suite
singleton:- A method called
add_fixture()
which registers a new fixture in the suite
- A method called
- Four new macros which define fixtures in the same way as scenarios:
- In
reporter::Reporter
,abstract_reporter::AbstractReporter
, andconsole_reporter::ConsoleReporter
:- Two new methods called
handle_fixture_start()
andhandle_fixture_end()
which are called before and after each fixture - Another new method called
set_show_fixtures()
which toggles how much information is reported about fixtures
- Two new methods called
- In the
expect
namespace:- A new template function called
fail_comparison()
, which is exactly likefail()
but formats its output specifically as a comparison failure
- A new template function called
Changed
Build system
- Upgrade the C++ version to C++20
- Renamed the
test
library totesting
to better fit with other library names (specificallyparsing
)
testing
library features
- Print a special message when there are no tests in a test suite
- Tests can now accept a
--show-fixtures
argument on the command line which causes the reporter to print more information about which fixtures run and when - The
SCENARIO
macro andScenarioRegistrar
type have been moved to thesuite
namespace - The console reporter will now display a count of total fixture invocations in the suite summary
- All reporters now require a third argument,
fixture_count
, to thehandle_suite_end()
method - The
EXPECT
family of macros now print much more detailed information when a test fails - In the
expect
namespace:- The
fail
function now takes more arguments and has been made into a template based on the type of value beingEXPECT
ed
- The
Fixed
parsing
library
- Compilation
cast truncates constant value
warning on MSVC
testing
library
- Disallow copying and moving the Suite singleton
- Incorrect include guard symbols
- Compilation warning on AppleClang:
[[nodiscard]]
on a function returningvoid
Build system
- Give a nice message from CMake instead of weird errors when trying to build for non-64-bit systems
0.1.0
Released on September 04, 2021.
Added
New libraries
core
library for fundamental types and functions used by everything elsetest
library for testing infrastructureunix
library for wrapping Unix-like APIswindows
library for wrapping Windows APIs
core
library features
core::constant_error
namespace, containing aConstantError
template for errors with a constant messagecore::error_chain
namespace, containing theErrorChain
class for building complex error typescore::none
namespace, containing theNone
type to use as a placeholdercore::resource_warden
namespace, containing a class template for cleaning up raw resources on scope exitcore::result
namespace, containing facilities for operations that can fail
test
library features
test::abstract_reporter
namespace, containing theAbstractReporter
interfacetest::cli
namespace, containing a functionexecute()
that can be called frommain()
test::console_reporter
namespace, containing a reporter that writes to stdouttest::expect
namespace, containing macros to express test assertionstest::outcome
namespace, containing types representing scenario outcomestest::reporter
namespace, containing factories for specific reporters and also a wrapper typetest::scenario
namespace, containing theScenario
type for representing a single test scenariotest::suite
namespace, containing theSuite
singleton used to hold all of the tests in a suite
unix
library features
unix::errno_error
namespace, containing utilities for working witherrno
unix::fs
namespace, containing wrappers for filesystem APIs on Unix-like systems
windows
library features
windows::fs
namespace, containing wrappers for filesystem APIs on Windowswindows::transcoding
namespace, containing functions for transcoding UTF8 with UTF16 for Windows APIswindows::windows_error
namespace, containing functions and a type for reading and formatting Windows errors
Build system features
AddCrucibleExecutable
module, which provides a wrapper foradd_executable()
AddCrucibleLibrary
module, which provides a wrapper foradd_library()
AddCrucibleTest
module, which provides a wrapper foradd_test()
EnableCompilerWarnings
module, which provides a function that enables common compiler warning flagsEnableRuntimeSanitizers
module, which provides a function that enables ASAN, TSAN, and UBSAN based on options- Write all final build outputs (executables and libraries) to
${PROJECT_BINARY_DIR}/artifacts
- Automatically export all symbols from all libraries when building Windows DLLs
Repository features
- Build dependencies in the README
- Build instructions in the README
- Test instructions in the README
- Attribution in the README