Compare commits

...

4 Commits

Author SHA1 Message Date
Ayaz Salikhov
f399749ee2 chore: Add black pre-commit hook (#6086)
This change adds Black as a pre-commit hook to format Python files.
2025-11-26 19:14:17 +00:00
Ayaz Salikhov
2ed4047840 chore: Make conan lockfile generation commands into a script (#6085)
This change moves the lockfile instructions into a script, and instead of removing packages it sets the Conan home directory to a temporary directory.

There are several advantages, such as:
* Not affecting the user's Conan home directory, so there is no need to remove packages.
* Only the script needs to be run, rather than several commands.
2025-11-26 18:43:14 +00:00
Ayaz Salikhov
4e25dc9291 chore: Update lockfile (#6083)
This change update recipes, to make sure we have the best compatibility with latest compilers and so on.
2025-11-26 17:54:36 +00:00
Bart
a18b30b765 docs: Update instructions how to (re)generate conan.lock file (#6070)
This change updates the instructions for how to generate a Conan lockfile that is compatible with Linux, macOS, and Windows.

Whenever Conan dependencies change, the Conan lock file needs to be regenerated. However, different OSes have slightly different requirements, and thus require slightly different dependencies. Luckily a single `conan.lock` file can be used, as long as the union of dependencies is included.

The current instructions in the `BUILD.md` file are insufficient to regenerate the lock file such that it is compatible with all OSes, which this change addresses. The three profiles contain the bare minimum needed to generate the lockfile; it does not particularly matter whether the build type is Debug or Release, for instance.
2025-11-26 17:28:06 +00:00
11 changed files with 424 additions and 255 deletions

View File

@@ -2,11 +2,12 @@
import argparse import argparse
import itertools import itertools
import json import json
from pathlib import Path
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path
THIS_DIR = Path(__file__).parent.resolve() THIS_DIR = Path(__file__).parent.resolve()
@dataclass @dataclass
class Config: class Config:
architecture: list[dict] architecture: list[dict]
@@ -14,7 +15,8 @@ class Config:
build_type: list[str] build_type: list[str]
cmake_args: list[str] cmake_args: list[str]
'''
"""
Generate a strategy matrix for GitHub Actions CI. Generate a strategy matrix for GitHub Actions CI.
On each PR commit we will build a selection of Debian, RHEL, Ubuntu, MacOS, and On each PR commit we will build a selection of Debian, RHEL, Ubuntu, MacOS, and
@@ -27,19 +29,23 @@ We will further set additional CMake arguments as follows:
- All release builds will have the `assert` option. - All release builds will have the `assert` option.
- Certain Debian Bookworm configurations will change the reference fee, enable - Certain Debian Bookworm configurations will change the reference fee, enable
codecov, and enable voidstar in PRs. codecov, and enable voidstar in PRs.
''' """
def generate_strategy_matrix(all: bool, config: Config) -> list: def generate_strategy_matrix(all: bool, config: Config) -> list:
configurations = [] configurations = []
for architecture, os, build_type, cmake_args in itertools.product(config.architecture, config.os, config.build_type, config.cmake_args): for architecture, os, build_type, cmake_args in itertools.product(
config.architecture, config.os, config.build_type, config.cmake_args
):
# The default CMake target is 'all' for Linux and MacOS and 'install' # The default CMake target is 'all' for Linux and MacOS and 'install'
# for Windows, but it can get overridden for certain configurations. # for Windows, but it can get overridden for certain configurations.
cmake_target = 'install' if os["distro_name"] == 'windows' else 'all' cmake_target = "install" if os["distro_name"] == "windows" else "all"
# We build and test all configurations by default, except for Windows in # We build and test all configurations by default, except for Windows in
# Debug, because it is too slow, as well as when code coverage is # Debug, because it is too slow, as well as when code coverage is
# enabled as that mode already runs the tests. # enabled as that mode already runs the tests.
build_only = False build_only = False
if os['distro_name'] == 'windows' and build_type == 'Debug': if os["distro_name"] == "windows" and build_type == "Debug":
build_only = True build_only = True
# Only generate a subset of configurations in PRs. # Only generate a subset of configurations in PRs.
@@ -54,21 +60,46 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
# - Bookworm using Clang 17: Release and no Unity on linux/amd64, # - Bookworm using Clang 17: Release and no Unity on linux/amd64,
# set the reference fee to 1000. # set the reference fee to 1000.
# - Bookworm using Clang 20: Debug and Unity on linux/amd64. # - Bookworm using Clang 20: Debug and Unity on linux/amd64.
if os['distro_name'] == 'debian': if os["distro_name"] == "debian":
skip = True skip = True
if os['distro_version'] == 'bookworm': if os["distro_version"] == "bookworm":
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-13' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': if (
cmake_args = f'-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}' f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-13"
and build_type == "Release"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=500 {cmake_args}"
skip = False skip = False
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-15' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
and build_type == "Debug"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/amd64"
):
skip = False skip = False
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-16' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/arm64': if (
cmake_args = f'-Dvoidstar=ON {cmake_args}' f"{os['compiler_name']}-{os['compiler_version']}" == "clang-16"
and build_type == "Debug"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/arm64"
):
cmake_args = f"-Dvoidstar=ON {cmake_args}"
skip = False skip = False
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-17' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': if (
cmake_args = f'-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}' f"{os['compiler_name']}-{os['compiler_version']}" == "clang-17"
and build_type == "Release"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}"
skip = False skip = False
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-20' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20"
and build_type == "Debug"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "linux/amd64"
):
skip = False skip = False
if skip: if skip:
continue continue
@@ -76,13 +107,23 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
# RHEL: # RHEL:
# - 9 using GCC 12: Debug and Unity on linux/amd64. # - 9 using GCC 12: Debug and Unity on linux/amd64.
# - 10 using Clang: Release and no Unity on linux/amd64. # - 10 using Clang: Release and no Unity on linux/amd64.
if os['distro_name'] == 'rhel': if os["distro_name"] == "rhel":
skip = True skip = True
if os['distro_version'] == '9': if os["distro_version"] == "9":
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "linux/amd64"
):
skip = False skip = False
elif os['distro_version'] == '10': elif os["distro_version"] == "10":
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-any' and build_type == 'Release' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-any"
and build_type == "Release"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/amd64"
):
skip = False skip = False
if skip: if skip:
continue continue
@@ -92,104 +133,169 @@ def generate_strategy_matrix(all: bool, config: Config) -> list:
# - Noble using GCC 14: Release and Unity on linux/amd64. # - Noble using GCC 14: Release and Unity on linux/amd64.
# - Noble using Clang 18: Debug and no Unity on linux/amd64. # - Noble using Clang 18: Debug and no Unity on linux/amd64.
# - Noble using Clang 19: Release and Unity on linux/arm64. # - Noble using Clang 19: Release and Unity on linux/arm64.
if os['distro_name'] == 'ubuntu': if os["distro_name"] == "ubuntu":
skip = True skip = True
if os['distro_version'] == 'jammy': if os["distro_version"] == "jammy":
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-12' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/arm64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
and build_type == "Debug"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/arm64"
):
skip = False skip = False
elif os['distro_version'] == 'noble': elif os["distro_version"] == "noble":
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-14' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/amd64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"
and build_type == "Release"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "linux/amd64"
):
skip = False skip = False
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-18' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-18"
and build_type == "Debug"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/amd64"
):
skip = False skip = False
if f'{os['compiler_name']}-{os['compiler_version']}' == 'clang-19' and build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'linux/arm64': if (
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-19"
and build_type == "Release"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "linux/arm64"
):
skip = False skip = False
if skip: if skip:
continue continue
# MacOS: # MacOS:
# - Debug and no Unity on macos/arm64. # - Debug and no Unity on macos/arm64.
if os['distro_name'] == 'macos' and not (build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'macos/arm64'): if os["distro_name"] == "macos" and not (
build_type == "Debug"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "macos/arm64"
):
continue continue
# Windows: # Windows:
# - Release and Unity on windows/amd64. # - Release and Unity on windows/amd64.
if os['distro_name'] == 'windows' and not (build_type == 'Release' and '-Dunity=ON' in cmake_args and architecture['platform'] == 'windows/amd64'): if os["distro_name"] == "windows" and not (
build_type == "Release"
and "-Dunity=ON" in cmake_args
and architecture["platform"] == "windows/amd64"
):
continue continue
# Additional CMake arguments. # Additional CMake arguments.
cmake_args = f'{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON' cmake_args = f"{cmake_args} -Dtests=ON -Dwerr=ON -Dxrpld=ON"
if not f'{os['compiler_name']}-{os['compiler_version']}' in ['gcc-12', 'clang-16']: if not f"{os['compiler_name']}-{os['compiler_version']}" in [
cmake_args = f'{cmake_args} -Dwextra=ON' "gcc-12",
if build_type == 'Release': "clang-16",
cmake_args = f'{cmake_args} -Dassert=ON' ]:
cmake_args = f"{cmake_args} -Dwextra=ON"
if build_type == "Release":
cmake_args = f"{cmake_args} -Dassert=ON"
# We skip all RHEL on arm64 due to a build failure that needs further # We skip all RHEL on arm64 due to a build failure that needs further
# investigation. # investigation.
if os['distro_name'] == 'rhel' and architecture['platform'] == 'linux/arm64': if os["distro_name"] == "rhel" and architecture["platform"] == "linux/arm64":
continue continue
# We skip all clang 20+ on arm64 due to Boost build error. # We skip all clang 20+ on arm64 due to Boost build error.
if f'{os['compiler_name']}-{os['compiler_version']}' in ['clang-20', 'clang-21'] and architecture['platform'] == 'linux/arm64': if (
f"{os['compiler_name']}-{os['compiler_version']}"
in ["clang-20", "clang-21"]
and architecture["platform"] == "linux/arm64"
):
continue continue
# Enable code coverage for Debian Bookworm using GCC 15 in Debug and no # Enable code coverage for Debian Bookworm using GCC 15 in Debug and no
# Unity on linux/amd64 # Unity on linux/amd64
if f'{os['compiler_name']}-{os['compiler_version']}' == 'gcc-15' and build_type == 'Debug' and '-Dunity=OFF' in cmake_args and architecture['platform'] == 'linux/amd64': if (
cmake_args = f'-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}' f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
and build_type == "Debug"
and "-Dunity=OFF" in cmake_args
and architecture["platform"] == "linux/amd64"
):
cmake_args = f"-Dcoverage=ON -Dcoverage_format=xml -DCODE_COVERAGE_VERBOSE=ON -DCMAKE_C_FLAGS=-O0 -DCMAKE_CXX_FLAGS=-O0 {cmake_args}"
# Generate a unique name for the configuration, e.g. macos-arm64-debug # Generate a unique name for the configuration, e.g. macos-arm64-debug
# or debian-bookworm-gcc-12-amd64-release-unity. # or debian-bookworm-gcc-12-amd64-release-unity.
config_name = os['distro_name'] config_name = os["distro_name"]
if (n := os['distro_version']) != '': if (n := os["distro_version"]) != "":
config_name += f'-{n}' config_name += f"-{n}"
if (n := os['compiler_name']) != '': if (n := os["compiler_name"]) != "":
config_name += f'-{n}' config_name += f"-{n}"
if (n := os['compiler_version']) != '': if (n := os["compiler_version"]) != "":
config_name += f'-{n}' config_name += f"-{n}"
config_name += f'-{architecture['platform'][architecture['platform'].find('/')+1:]}' config_name += (
config_name += f'-{build_type.lower()}' f"-{architecture['platform'][architecture['platform'].find('/') + 1 :]}"
if '-Dunity=ON' in cmake_args: )
config_name += '-unity' config_name += f"-{build_type.lower()}"
if "-Dunity=ON" in cmake_args:
config_name += "-unity"
# Add the configuration to the list, with the most unique fields first, # Add the configuration to the list, with the most unique fields first,
# so that they are easier to identify in the GitHub Actions UI, as long # so that they are easier to identify in the GitHub Actions UI, as long
# names get truncated. # names get truncated.
configurations.append({ configurations.append(
'config_name': config_name, {
'cmake_args': cmake_args, "config_name": config_name,
'cmake_target': cmake_target, "cmake_args": cmake_args,
'build_only': build_only, "cmake_target": cmake_target,
'build_type': build_type, "build_only": build_only,
'os': os, "build_type": build_type,
'architecture': architecture, "os": os,
}) "architecture": architecture,
}
)
return configurations return configurations
def read_config(file: Path) -> Config: def read_config(file: Path) -> Config:
config = json.loads(file.read_text()) config = json.loads(file.read_text())
if config['architecture'] is None or config['os'] is None or config['build_type'] is None or config['cmake_args'] is None: if (
raise Exception('Invalid configuration file.') config["architecture"] is None
or config["os"] is None
or config["build_type"] is None
or config["cmake_args"] is None
):
raise Exception("Invalid configuration file.")
return Config(**config) return Config(**config)
if __name__ == '__main__': if __name__ == "__main__":
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('-a', '--all', help='Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).', action="store_true") parser.add_argument(
parser.add_argument('-c', '--config', help='Path to the JSON file containing the strategy matrix configurations.', required=False, type=Path) "-a",
"--all",
help="Set to generate all configurations (generally used when merging a PR) or leave unset to generate a subset of configurations (generally used when committing to a PR).",
action="store_true",
)
parser.add_argument(
"-c",
"--config",
help="Path to the JSON file containing the strategy matrix configurations.",
required=False,
type=Path,
)
args = parser.parse_args() args = parser.parse_args()
matrix = [] matrix = []
if args.config is None or args.config == '': if args.config is None or args.config == "":
matrix += generate_strategy_matrix(args.all, read_config(THIS_DIR / "linux.json")) matrix += generate_strategy_matrix(
matrix += generate_strategy_matrix(args.all, read_config(THIS_DIR / "macos.json")) args.all, read_config(THIS_DIR / "linux.json")
matrix += generate_strategy_matrix(args.all, read_config(THIS_DIR / "windows.json")) )
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "macos.json")
)
matrix += generate_strategy_matrix(
args.all, read_config(THIS_DIR / "windows.json")
)
else: else:
matrix += generate_strategy_matrix(args.all, read_config(args.config)) matrix += generate_strategy_matrix(args.all, read_config(args.config))
# Generate the strategy matrix. # Generate the strategy matrix.
print(f'matrix={json.dumps({"include": matrix})}') print(f"matrix={json.dumps({'include': matrix})}")

View File

@@ -31,6 +31,11 @@ repos:
hooks: hooks:
- id: prettier - id: prettier
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.11.0
hooks:
- id: black
exclude: | exclude: |
(?x)^( (?x)^(
external/.*| external/.*|

View File

@@ -88,6 +88,13 @@ These instructions assume a basic familiarity with Conan and CMake. If you are
unfamiliar with Conan, then please read [this crash course](./docs/build/conan.md) or the official unfamiliar with Conan, then please read [this crash course](./docs/build/conan.md) or the official
[Getting Started][3] walkthrough. [Getting Started][3] walkthrough.
#### Conan lockfile
To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html),
which has to be updated every time dependencies change.
Please see the [instructions on how to regenerate the lockfile](conan/lockfile/README.md).
#### Default profile #### Default profile
We recommend that you import the provided `conan/profiles/default` profile: We recommend that you import the provided `conan/profiles/default` profile:
@@ -450,33 +457,6 @@ tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
The location of `rippled` binary in your build directory depends on your The location of `rippled` binary in your build directory depends on your
CMake generator. Pass `--help` to see the rest of the command line options. CMake generator. Pass `--help` to see the rest of the command line options.
#### Conan lockfile
To achieve reproducible dependencies, we use [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html).
The `conan.lock` file in the repository contains a "snapshot" of the current dependencies.
It is implicitly used when running `conan` commands, you don't need to specify it.
You have to update this file every time you add a new dependency or change a revision or version of an existing dependency.
> [!NOTE]
> Conan uses local cache by default when creating a lockfile.
>
> To ensure, that lockfile creation works the same way on all developer machines, you should clear the local cache before creating a new lockfile.
To create a new lockfile, run the following commands in the repository root:
```bash
conan remove '*' --confirm
rm conan.lock
# This ensure that xrplf remote is the first to be consulted
conan remote add --force --index 0 xrplf https://conan.ripplex.io
conan lock create . -o '&:jemalloc=True' -o '&:rocksdb=True'
```
> [!NOTE]
> If some dependencies are exclusive for some OS, you may need to run the last command for them adding `--profile:all <PROFILE>`.
## Coverage report ## Coverage report
The coverage report is intended for developers using compilers GCC The coverage report is intended for developers using compilers GCC

View File

@@ -7,31 +7,32 @@
"soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318", "soci/4.0.3#a9f8d773cd33e356b5879a4b0564f287%1756234262.318",
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246", "snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1756234314.246",
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1762797952.535", "rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1762797952.535",
"re2/20230301#dfd6e2bf050eb90ddd8729cfb4c844a4%1756234257.976", "re2/20230301#ca3b241baec15bd31ea9187150e0b333%1764175362.029",
"protobuf/3.21.12#d927114e28de9f4691a6bbcdd9a529d1%1756234251.614", "protobuf/3.21.12#44ee56c0a6eea0c19aeeaca680370b88%1764175361.456",
"openssl/3.5.4#a1d5835cc6ed5c5b8f3cd5b9b5d24205%1760106486.594", "openssl/3.5.4#a1d5835cc6ed5c5b8f3cd5b9b5d24205%1760106486.594",
"nudb/2.0.9#fb8dfd1a5557f5e0528114c2da17721e%1763150366.909", "nudb/2.0.9#fb8dfd1a5557f5e0528114c2da17721e%1763150366.909",
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1756234228.999", "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1756234228.999",
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1756223727.64", "libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1756223727.64",
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1756230911.03", "libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1756230911.03",
"libarchive/3.8.1#5cf685686322e906cb42706ab7e099a8%1756234256.696", "libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1764175360.142",
"jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244", "jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244",
"grpc/1.50.1#02291451d1e17200293a409410d1c4e1%1756234248.958", "grpc/1.50.1#02291451d1e17200293a409410d1c4e1%1756234248.958",
"doctest/2.4.12#eb9fb352fb2fdfc8abb17ec270945165%1762797941.757", "doctest/2.4.12#eb9fb352fb2fdfc8abb17ec270945165%1762797941.757",
"date/3.0.4#f74bbba5a08fa388256688743136cb6f%1756234217.493", "date/3.0.4#862e11e80030356b53c2c38599ceb32b%1763584497.32",
"c-ares/1.34.5#b78b91e7cfb1f11ce777a285bbf169c6%1756234217.915", "c-ares/1.34.5#5581c2b62a608b40bb85d965ab3ec7c8%1764175359.429",
"bzip2/1.0.8#00b4a4658791c1f06914e087f0e792f5%1756234261.716", "bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1764175359.429",
"boost/1.88.0#8852c0b72ce8271fb8ff7c53456d4983%1756223752.326", "boost/1.88.0#8852c0b72ce8271fb8ff7c53456d4983%1756223752.326",
"abseil/20230802.1#f0f91485b111dc9837a68972cb19ca7b%1756234220.907" "abseil/20230802.1#90ba607d4ee8fb5fb157c3db540671fc%1764175359.429"
], ],
"build_requires": [ "build_requires": [
"zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497", "zlib/1.3.1#b8bc2603263cf7eccbd6e17e66b0ed76%1756234269.497",
"strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1756234281.733", "strawberryperl/5.32.1.1#707032463aa0620fa17ec0d887f5fe41%1756234281.733",
"protobuf/3.21.12#d927114e28de9f4691a6bbcdd9a529d1%1756234251.614", "protobuf/3.21.12#44ee56c0a6eea0c19aeeaca680370b88%1764175361.456",
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1756234232.901", "nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1756234232.901",
"msys2/cci.latest#5b73b10144f73cc5bfe0572ed9be39e1%1751977009.857", "msys2/cci.latest#5b73b10144f73cc5bfe0572ed9be39e1%1751977009.857",
"m4/1.4.19#f119296e5c4772b3bb7ab060ae8f417b%1760707875.678", "m4/1.4.19#70dc8bbb33e981d119d2acc0175cf381%1763158052.846",
"cmake/3.31.8#dde3bde00bb843687e55aea5afa0e220%1756234232.89", "cmake/4.2.0#ae0a44f44a1ef9ab68fd4b3e9a1f8671%1764175359.44",
"cmake/3.31.10#313d16a1aa16bbdb2ca0792467214b76%1764175359.429",
"b2/5.3.3#107c15377719889654eb9a162a673975%1756234226.28", "b2/5.3.3#107c15377719889654eb9a162a673975%1756234226.28",
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56", "automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
"autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86" "autoconf/2.71#51077f068e61700d65bb05541ea1e4b0%1731054366.86"
@@ -48,14 +49,11 @@
"boost/1.83.0": [ "boost/1.83.0": [
"boost/1.88.0" "boost/1.88.0"
], ],
"sqlite3/[>=3.44 <4]": [ "sqlite3/3.44.2": [
"sqlite3/3.49.1" "sqlite3/3.49.1"
], ],
"lz4/[>=1.9.4 <2]": [ "lz4/[>=1.9.4 <2]": [
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504" "lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504"
],
"sqlite3/3.44.2": [
"sqlite3/3.49.1"
] ]
}, },
"config_requires": [] "config_requires": []

12
conan/lockfile/README.md Normal file
View File

@@ -0,0 +1,12 @@
# Conan lockfile
To achieve reproducible dependencies, we use a [Conan lockfile](https://docs.conan.io/2/tutorial/versioning/lockfiles.html).
The `conan.lock` file in the repository contains a "snapshot" of the current
dependencies. It is implicitly used when running `conan` commands, so you don't
need to specify it.
You have to update this file every time you add a new dependency or change a
revision or version of an existing dependency.
To update a lockfile, run from the repository root: `./conan/lockfile/regenerate.sh`

View File

@@ -0,0 +1,8 @@
[settings]
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=20
compiler.libcxx=libstdc++11
compiler.version=13
os=Linux

View File

@@ -0,0 +1,8 @@
[settings]
arch=armv8
build_type=Release
compiler=apple-clang
compiler.cppstd=20
compiler.libcxx=libc++
compiler.version=17.0
os=Macos

36
conan/lockfile/regenerate.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -ex
TEMP_DIR=$(mktemp -d)
trap "rm -rf $TEMP_DIR" EXIT
echo "Using temporary CONAN_HOME: $TEMP_DIR"
# We use a temporary Conan home to avoid polluting the user's existing Conan
# configuration and to not use local cache (which leads to non-reproducible lockfiles).
export CONAN_HOME="$TEMP_DIR"
# Ensure that the xrplf remote is the first to be consulted, so any recipes we
# patched are used. We also add it there to not created huge diff when the
# official Conan Center Index is updated.
conan remote add --force --index 0 xrplf https://conan.ripplex.io
# Delete any existing lockfile.
rm -f conan.lock
# Create a new lockfile that is compatible with Linux, macOS, and Windows. The
# first create command will create a new lockfile, while the subsequent create
# commands will merge any additional dependencies into the created lockfile.
conan lock create . \
--options '&:jemalloc=True' \
--options '&:rocksdb=True' \
--profile:all=conan/lockfile/linux.profile
conan lock create . \
--options '&:jemalloc=True' \
--options '&:rocksdb=True' \
--profile:all=conan/lockfile/macos.profile
conan lock create . \
--options '&:jemalloc=True' \
--options '&:rocksdb=True' \
--profile:all=conan/lockfile/windows.profile

View File

@@ -0,0 +1,9 @@
[settings]
arch=x86_64
build_type=Release
compiler=msvc
compiler.cppstd=20
compiler.runtime=dynamic
compiler.runtime_type=Release
compiler.version=194
os=Windows

View File

@@ -1,149 +1,155 @@
from conan import ConanFile, __version__ as conan_version
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
import re import re
class Xrpl(ConanFile): from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
name = 'xrpl'
license = 'ISC' from conan import ConanFile
author = 'John Freeman <jfreeman@ripple.com>' from conan import __version__ as conan_version
url = 'https://github.com/xrplf/rippled'
description = 'The XRP Ledger'
settings = 'os', 'compiler', 'build_type', 'arch' class Xrpl(ConanFile):
name = "xrpl"
license = "ISC"
author = "John Freeman <jfreeman@ripple.com>"
url = "https://github.com/xrplf/rippled"
description = "The XRP Ledger"
settings = "os", "compiler", "build_type", "arch"
options = { options = {
'assertions': [True, False], "assertions": [True, False],
'coverage': [True, False], "coverage": [True, False],
'fPIC': [True, False], "fPIC": [True, False],
'jemalloc': [True, False], "jemalloc": [True, False],
'rocksdb': [True, False], "rocksdb": [True, False],
'shared': [True, False], "shared": [True, False],
'static': [True, False], "static": [True, False],
'tests': [True, False], "tests": [True, False],
'unity': [True, False], "unity": [True, False],
'xrpld': [True, False], "xrpld": [True, False],
} }
requires = [ requires = [
'grpc/1.50.1', "grpc/1.50.1",
'libarchive/3.8.1', "libarchive/3.8.1",
'nudb/2.0.9', "nudb/2.0.9",
'openssl/3.5.4', "openssl/3.5.4",
'soci/4.0.3', "soci/4.0.3",
'zlib/1.3.1', "zlib/1.3.1",
] ]
test_requires = [ test_requires = [
'doctest/2.4.12', "doctest/2.4.12",
] ]
tool_requires = [ tool_requires = [
'protobuf/3.21.12', "protobuf/3.21.12",
] ]
default_options = { default_options = {
'assertions': False, "assertions": False,
'coverage': False, "coverage": False,
'fPIC': True, "fPIC": True,
'jemalloc': False, "jemalloc": False,
'rocksdb': True, "rocksdb": True,
'shared': False, "shared": False,
'static': True, "static": True,
'tests': False, "tests": False,
'unity': False, "unity": False,
'xrpld': False, "xrpld": False,
"date/*:header_only": True,
'date/*:header_only': True, "grpc/*:shared": False,
'grpc/*:shared': False, "grpc/*:secure": True,
'grpc/*:secure': True, "libarchive/*:shared": False,
'libarchive/*:shared': False, "libarchive/*:with_acl": False,
'libarchive/*:with_acl': False, "libarchive/*:with_bzip2": False,
'libarchive/*:with_bzip2': False, "libarchive/*:with_cng": False,
'libarchive/*:with_cng': False, "libarchive/*:with_expat": False,
'libarchive/*:with_expat': False, "libarchive/*:with_iconv": False,
'libarchive/*:with_iconv': False, "libarchive/*:with_libxml2": False,
'libarchive/*:with_libxml2': False, "libarchive/*:with_lz4": True,
'libarchive/*:with_lz4': True, "libarchive/*:with_lzma": False,
'libarchive/*:with_lzma': False, "libarchive/*:with_lzo": False,
'libarchive/*:with_lzo': False, "libarchive/*:with_nettle": False,
'libarchive/*:with_nettle': False, "libarchive/*:with_openssl": False,
'libarchive/*:with_openssl': False, "libarchive/*:with_pcreposix": False,
'libarchive/*:with_pcreposix': False, "libarchive/*:with_xattr": False,
'libarchive/*:with_xattr': False, "libarchive/*:with_zlib": False,
'libarchive/*:with_zlib': False, "lz4/*:shared": False,
'lz4/*:shared': False, "openssl/*:shared": False,
'openssl/*:shared': False, "protobuf/*:shared": False,
'protobuf/*:shared': False, "protobuf/*:with_zlib": True,
'protobuf/*:with_zlib': True, "rocksdb/*:enable_sse": False,
'rocksdb/*:enable_sse': False, "rocksdb/*:lite": False,
'rocksdb/*:lite': False, "rocksdb/*:shared": False,
'rocksdb/*:shared': False, "rocksdb/*:use_rtti": True,
'rocksdb/*:use_rtti': True, "rocksdb/*:with_jemalloc": False,
'rocksdb/*:with_jemalloc': False, "rocksdb/*:with_lz4": True,
'rocksdb/*:with_lz4': True, "rocksdb/*:with_snappy": True,
'rocksdb/*:with_snappy': True, "snappy/*:shared": False,
'snappy/*:shared': False, "soci/*:shared": False,
'soci/*:shared': False, "soci/*:with_sqlite3": True,
'soci/*:with_sqlite3': True, "soci/*:with_boost": True,
'soci/*:with_boost': True, "xxhash/*:shared": False,
'xxhash/*:shared': False,
} }
def set_version(self): def set_version(self):
if self.version is None: if self.version is None:
path = f'{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp' path = f"{self.recipe_folder}/src/libxrpl/protocol/BuildInfo.cpp"
regex = r'versionString\s?=\s?\"(.*)\"' regex = r"versionString\s?=\s?\"(.*)\""
with open(path, encoding='utf-8') as file: with open(path, encoding="utf-8") as file:
matches = (re.search(regex, line) for line in file) matches = (re.search(regex, line) for line in file)
match = next(m for m in matches if m) match = next(m for m in matches if m)
self.version = match.group(1) self.version = match.group(1)
def configure(self): def configure(self):
if self.settings.compiler == 'apple-clang': if self.settings.compiler == "apple-clang":
self.options['boost'].visibility = 'global' self.options["boost"].visibility = "global"
if self.settings.compiler in ['clang', 'gcc']: if self.settings.compiler in ["clang", "gcc"]:
self.options['boost'].without_cobalt = True self.options["boost"].without_cobalt = True
def requirements(self): def requirements(self):
# Conan 2 requires transitive headers to be specified # Conan 2 requires transitive headers to be specified
transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {} transitive_headers_opt = (
self.requires('boost/1.88.0', force=True, **transitive_headers_opt) {"transitive_headers": True} if conan_version.split(".")[0] == "2" else {}
self.requires('date/3.0.4', **transitive_headers_opt) )
self.requires('lz4/1.10.0', force=True) self.requires("boost/1.88.0", force=True, **transitive_headers_opt)
self.requires('protobuf/3.21.12', force=True) self.requires("date/3.0.4", **transitive_headers_opt)
self.requires('sqlite3/3.49.1', force=True) self.requires("lz4/1.10.0", force=True)
self.requires("protobuf/3.21.12", force=True)
self.requires("sqlite3/3.49.1", force=True)
if self.options.jemalloc: if self.options.jemalloc:
self.requires('jemalloc/5.3.0') self.requires("jemalloc/5.3.0")
if self.options.rocksdb: if self.options.rocksdb:
self.requires('rocksdb/10.5.1') self.requires("rocksdb/10.5.1")
self.requires('xxhash/0.8.3', **transitive_headers_opt) self.requires("xxhash/0.8.3", **transitive_headers_opt)
exports_sources = ( exports_sources = (
'CMakeLists.txt', "CMakeLists.txt",
'cfg/*', "cfg/*",
'cmake/*', "cmake/*",
'external/*', "external/*",
'include/*', "include/*",
'src/*', "src/*",
) )
def layout(self): def layout(self):
cmake_layout(self) cmake_layout(self)
# Fix this setting to follow the default introduced in Conan 1.48 # Fix this setting to follow the default introduced in Conan 1.48
# to align with our build instructions. # to align with our build instructions.
self.folders.generators = 'build/generators' self.folders.generators = "build/generators"
generators = "CMakeDeps"
generators = 'CMakeDeps'
def generate(self): def generate(self):
tc = CMakeToolchain(self) tc = CMakeToolchain(self)
tc.variables['tests'] = self.options.tests tc.variables["tests"] = self.options.tests
tc.variables['assert'] = self.options.assertions tc.variables["assert"] = self.options.assertions
tc.variables['coverage'] = self.options.coverage tc.variables["coverage"] = self.options.coverage
tc.variables['jemalloc'] = self.options.jemalloc tc.variables["jemalloc"] = self.options.jemalloc
tc.variables['rocksdb'] = self.options.rocksdb tc.variables["rocksdb"] = self.options.rocksdb
tc.variables['BUILD_SHARED_LIBS'] = self.options.shared tc.variables["BUILD_SHARED_LIBS"] = self.options.shared
tc.variables['static'] = self.options.static tc.variables["static"] = self.options.static
tc.variables['unity'] = self.options.unity tc.variables["unity"] = self.options.unity
tc.variables['xrpld'] = self.options.xrpld tc.variables["xrpld"] = self.options.xrpld
tc.generate() tc.generate()
def build(self): def build(self):
@@ -158,40 +164,40 @@ class Xrpl(ConanFile):
cmake.install() cmake.install()
def package_info(self): def package_info(self):
libxrpl = self.cpp_info.components['libxrpl'] libxrpl = self.cpp_info.components["libxrpl"]
libxrpl.libs = [ libxrpl.libs = [
'xrpl', "xrpl",
'xrpl.libpb', "xrpl.libpb",
'ed25519', "ed25519",
'secp256k1', "secp256k1",
] ]
# TODO: Fix the protobufs to include each other relative to # TODO: Fix the protobufs to include each other relative to
# `include/`, not `include/ripple/proto/`. # `include/`, not `include/ripple/proto/`.
libxrpl.includedirs = ['include', 'include/ripple/proto'] libxrpl.includedirs = ["include", "include/ripple/proto"]
libxrpl.requires = [ libxrpl.requires = [
'boost::headers', "boost::headers",
'boost::chrono', "boost::chrono",
'boost::container', "boost::container",
'boost::coroutine', "boost::coroutine",
'boost::date_time', "boost::date_time",
'boost::filesystem', "boost::filesystem",
'boost::json', "boost::json",
'boost::program_options', "boost::program_options",
'boost::process', "boost::process",
'boost::regex', "boost::regex",
'boost::system', "boost::system",
'boost::thread', "boost::thread",
'date::date', "date::date",
'grpc::grpc++', "grpc::grpc++",
'libarchive::libarchive', "libarchive::libarchive",
'lz4::lz4', "lz4::lz4",
'nudb::nudb', "nudb::nudb",
'openssl::crypto', "openssl::crypto",
'protobuf::libprotobuf', "protobuf::libprotobuf",
'soci::soci', "soci::soci",
'sqlite3::sqlite', "sqlite3::sqlite",
'xxhash::xxhash', "xxhash::xxhash",
'zlib::zlib', "zlib::zlib",
] ]
if self.options.rocksdb: if self.options.rocksdb:
libxrpl.requires.append('rocksdb::librocksdb') libxrpl.requires.append("rocksdb::librocksdb")

View File

@@ -1,28 +1,29 @@
from pathlib import Path from pathlib import Path
from conan import ConanFile
from conan.tools.build import can_run from conan.tools.build import can_run
from conan.tools.cmake import CMake, cmake_layout from conan.tools.cmake import CMake, cmake_layout
from conan import ConanFile
class Example(ConanFile): class Example(ConanFile):
name = "example"
license = "ISC"
author = "John Freeman <jfreeman08@gmail.com>, Michael Legleux <mlegleux@ripple.com"
name = 'example' settings = "os", "compiler", "build_type", "arch"
license = 'ISC'
author = 'John Freeman <jfreeman08@gmail.com>, Michael Legleux <mlegleux@ripple.com'
settings = 'os', 'compiler', 'build_type', 'arch'
requires = ["xrpl/head"] requires = ["xrpl/head"]
default_options = { default_options = {
'xrpl/*:xrpld': False, "xrpl/*:xrpld": False,
} }
generators = ['CMakeDeps', 'CMakeToolchain'] generators = ["CMakeDeps", "CMakeToolchain"]
def set_version(self): def set_version(self):
if self.version is None: if self.version is None:
self.version = '0.1.0' self.version = "0.1.0"
def layout(self): def layout(self):
cmake_layout(self) cmake_layout(self)