Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ See https://clang.llvm.org/docs/AddressSanitizer.html for more information.

*Note*: ASan will ignore any memory errors in Rust code unless you build with
Rust's ASan support. And building with Rust's ASan support requires configuring
with `--enable-unified-rust-unsafe-for-production`. See below on "unified Rust
with `--enable-fastdev-unsafe-for-production`. See below on "fastdev Rust
builds".

*Note*: Rust's ASan support also requires a nightly compiler and the rust-src
Expand Down Expand Up @@ -156,7 +156,7 @@ See https://clang.llvm.org/docs/ThreadSanitizer.html for more information.
*Note*: Since Rust code is run on multiple threads and those threads are
launched _from C++_ TSan will report races in Rust code unless you build with
Rust's TSan support. And building with Rust's TSan support requires configuring
with `--enable-unified-rust-unsafe-for-production`.
with `--enable-fastdev-unsafe-for-production`.

*Note*: Rust's ASan support also requires a nightly compiler and the rust-src
component. Install these with:
Expand Down Expand Up @@ -294,7 +294,7 @@ files. You should then inspect to see that only the transactions you expected to
see change did so. If so, commit the changes as a new set of baselines for
future tests.

## Unified and non-unified Rust builds
## Fastdev and non-unified Rust builds

As of protocol 20, some components of stellar-core are written in Rust (notably
soroban).
Expand Down Expand Up @@ -331,23 +331,29 @@ and it _usually_ works. But there are two cases you might not want it.
the stdlib and producing some sort of link-time dependency on crates that
are only used as procedural macros).

For both of these cases, we've added the ability to (optionally) switch back to
the normal way Rust expects you to build a crate that links multiple versions of
a dependency: with a single "unified" cargo invocation, at the top level. There
are two different ways to enable this:
For both of these cases, we've added a fastdev mode that switches back to the
normal way Rust expects you to build a crate, with a single cargo invocation at
the top level and only the current and next Soroban hosts compiled in. There are
two different ways to enable this:

- By configuring with `--enable-unified-rust-unsafe-for-production`, if one
wants to _build_ a stellar-core with unified rust.
- By configuring with `--enable-fastdev-unsafe-for-production`, if one wants
to _build_ a stellar-core with fastdev rust.

- By toggling the "unified" feature flag in the IDE (eg. using the "Rust
- By toggling the "fastdev" feature flag in the IDE (eg. using the "Rust
Feature Toggler" editor extension in VS code) if one merely wants to _edit_
a stellar-core with unified rust.
a stellar-core with fastdev rust.

The configure flag has got such a long and unwieldy name because _it will build
soroban with slightly different versions of transitive dependencies_, a
configuration we do _not_ want to ship in production builds.
soroban with fewer host versions and slightly different versions of transitive
dependencies_, a configuration we do _not_ want to ship in production builds.

It is fine for debugging though. In practice those different versions of
transitive dependencies are rarely "all that different". You will _probably_ not
be able to observe any differences. We just don't want to chance it in
production.

To reduce the set of possible configurations and flags, fastdev also acts as
a superset of `--enable-next-protocol-version-unsafe-for-production` (i.e. it
also turns on the `next` feature and links in whatever the next-protocol soroban
host is).

26 changes: 20 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,10 @@ lto = true
# (or you can build with `make RUST_PROFILE=dev` to get them built with
# debug-and-no-opt).
debug = true

[profile.fastdev]
inherits = "release"
lto = false
debug = "line-tables-only"
codegen-units = 16
split-debuginfo = "unpacked"
36 changes: 28 additions & 8 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,24 @@ AX_APPEND_COMPILE_FLAGS($WFLAGS)
AX_APPEND_COMPILE_FLAGS([-pthread])
AC_LANG_POP(C)

AC_ARG_ENABLE(unified-rust-unsafe-for-production,
AS_HELP_STRING([--enable-unified-rust-unsafe-for-production],
[Build rust crates as a single cargo library, risking version drift]))
AM_CONDITIONAL(UNIFIED_RUST, [test "x$enable_unified_rust_unsafe_for_production" = "xyes"])
AC_ARG_ENABLE(fastdev-unsafe-for-production,
AS_HELP_STRING([--enable-fastdev-unsafe-for-production],
[Build in fast development mode UNSAFE FOR PRODUCTION]))
AS_IF([test "x$enable_fastdev_unsafe_for_production" = "xyes"], [
AC_MSG_NOTICE([enabling fastdev build profile UNSAFE FOR PRODUCTION])
fastdev_cxx_version=`$CXX --version 2>/dev/null`
case "$fastdev_cxx_version" in
*clang*)
CXXFLAGS="$CXXFLAGS -gline-tables-only"
AC_MSG_NOTICE([added -gline-tables-only to CXXFLAGS])
;;
*)
AC_MSG_ERROR([fastdev build requires clang compiler])
;;
esac
])
AM_CONDITIONAL(ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION,
[test "x$enable_fastdev_unsafe_for_production" = "xyes"])

unset sanitizeopts

Expand All @@ -110,8 +124,8 @@ AC_ARG_ENABLE([asan],
AS_IF([test "x$enable_asan" = "xyes"], [
AC_MSG_NOTICE([ Enabling asan, see https://clang.llvm.org/docs/AddressSanitizer.html ])

AS_IF([test "xyes" != "x$enable_unified_rust_unsafe_for_production"], [
AC_MSG_WARN(Asan will not instrument rust without --enable-unified-rust-unsafe-for-production)
AS_IF([test "xyes" != "x$enable_fastdev_unsafe_for_production"], [
AC_MSG_WARN(Asan will not instrument rust without --enable-fastdev-unsafe-for-production)
])

sanitizeopts="address"
Expand All @@ -134,8 +148,8 @@ AC_ARG_ENABLE([threadsanitizer],
AS_IF([test "x$enable_threadsanitizer" = "xyes"], [
AC_MSG_NOTICE([ enabling thread-sanitizer, see https://clang.llvm.org/docs/ThreadSanitizer.html ])

AS_IF([test "xyes" != "x$enable_unified_rust_unsafe_for_production"], [
AC_MSG_ERROR(Enabling tsan requires --enable-unified-rust-unsafe-for-production)
AS_IF([test "xyes" != "x$enable_fastdev_unsafe_for_production"], [
AC_MSG_ERROR(Enabling tsan requires --enable-fastdev-unsafe-for-production)
])
AS_IF([test x != "x$sanitizeopts"], [
AC_MSG_ERROR(Cannot enable multiple sanitizers at once)
Expand Down Expand Up @@ -558,6 +572,12 @@ AM_CONDITIONAL(USE_SPDLOG, [test x$enable_spdlog != xno])
AC_ARG_ENABLE(next-protocol-version-unsafe-for-production,
AS_HELP_STRING([--enable-next-protocol-version-unsafe-for-production],
[Enable next protocol version UNSAFE FOR PRODUCTION]))
AS_IF([test "x$enable_fastdev_unsafe_for_production" = "xyes"], [
AS_IF([test "x$enable_next_protocol_version_unsafe_for_production" != "xyes"], [
AC_MSG_NOTICE([enabling next protocol version due to fastdev build profile])
])
enable_next_protocol_version_unsafe_for_production=yes
])
AM_CONDITIONAL(ENABLE_NEXT_PROTOCOL_VERSION_UNSAFE_FOR_PRODUCTION,
[test x$enable_next_protocol_version_unsafe_for_production = xyes])

Expand Down
49 changes: 32 additions & 17 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ else
CARGO_FEATURE_NEXT =
endif

if ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION
CARGO_FEATURE_FASTDEV = --features fastdev
else
CARGO_FEATURE_FASTDEV =
endif

main/XDRFilesSha256.cpp: $(SRC_X_FILES) Makefile $(top_srcdir)/hash-xdrs.sh
$(top_srcdir)/hash-xdrs.sh $(top_srcdir)/src/protocol-curr >$@

Expand Down Expand Up @@ -131,11 +137,12 @@ stellar_core_SOURCES += $(GENERATED_XDRQUERY_SOURCES) util/xdrquery/XDRQueryPars
BUILT_SOURCES += rust/RustBridge.h $(GENERATED_RUST_SOURCES)
stellar_core_SOURCES += rust/RustBridge.h $(GENERATED_RUST_SOURCES)

if UNIFIED_RUST
RUST_TOOLCHAIN_CHANNEL=nightly
else
RUST_TOOLCHAIN_FILE=$(top_srcdir)/rust-toolchain.toml
RUST_TOOLCHAIN_CHANNEL=$(shell sed -n 's/channel *= *"\([^"]*\)"/\1/p' $(RUST_TOOLCHAIN_FILE))
RUST_TOOLCHAIN_FILE_CHANNEL=$(shell sed -n 's/channel *= *"\([^"]*\)"/\1/p' $(RUST_TOOLCHAIN_FILE))
if ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION
RUST_TOOLCHAIN_CHANNEL=$(if $(findstring -fsanitize=,$(CXXFLAGS)),nightly,$(RUST_TOOLCHAIN_FILE_CHANNEL))
else
RUST_TOOLCHAIN_CHANNEL=$(RUST_TOOLCHAIN_FILE_CHANNEL)
endif
CARGO=cargo +$(RUST_TOOLCHAIN_CHANNEL)
RUSTC_WRAPPER=@RUSTC_WRAPPER@
Expand All @@ -151,22 +158,27 @@ RUST_BUILD_DIR=$(top_builddir)/src/rust
RUST_BIN_DIR=$(RUST_BUILD_DIR)/bin
RUST_TARGET_DIR=$(top_builddir)/target
RUST_CXXBRIDGE=$(RUST_BIN_DIR)/cxxbridge

if ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION
RUST_PROFILE=fastdev
else
RUST_PROFILE=release
endif

check-rust-profile: Makefile
@case "$(RUST_PROFILE)" in \
release|dev) ;; \
*) echo "Error: RUST_PROFILE must be 'release' or 'dev', got '$(RUST_PROFILE)'" >&2; exit 1;; \
release|dev|fastdev) ;; \
*) echo "Error: RUST_PROFILE must be 'release', 'dev', or 'fastdev', got '$(RUST_PROFILE)'" >&2; exit 1;; \
esac

# Of course, RUST_PROFILE can't be used as an argument directly because cargo
# doesn't let you pass --debug, that's the default! you can only pass --release.
# So we have to derive a new variable here.
RUST_PROFILE_ARG := $(if $(findstring release,$(RUST_PROFILE)),--release,)
RUST_PROFILE_ARG := $(if $(findstring fastdev,$(RUST_PROFILE)),--profile fastdev,$(if $(findstring release,$(RUST_PROFILE)),--release,))

# Also for even more nonsense reasons the debug profile name is actually `dev`
# but only in the command line, the target subdirectory gets called `debug`.
RUST_PROFILE_DIR := $(if $(findstring release,$(RUST_PROFILE)),release,debug)
RUST_PROFILE_DIR := $(if $(findstring fastdev,$(RUST_PROFILE)),fastdev,$(if $(findstring release,$(RUST_PROFILE)),release,debug))

RUST_DEP_TREE_STAMP=$(RUST_BUILD_DIR)/src/dep-trees/equal-trees.stamp
SOROBAN_LIBS_STAMP=$(RUST_BUILD_DIR)/soroban/soroban-libs.stamp
Expand Down Expand Up @@ -201,7 +213,11 @@ SOROBAN_BUILD_DIR=$(abspath $(RUST_BUILD_DIR))/soroban
# variable empty (and include or exclude submodules from the list of
# ALL_SOROBAN_PROTOCOLS as you see fit).

if ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION
ALL_SOROBAN_PROTOCOLS=p26
else
ALL_SOROBAN_PROTOCOLS=p21 p22 p23 p24 p25 p26
endif
WIP_SOROBAN_PROTOCOL=p27

CARGO_XDR_FEATURE_FLAGS =
Expand Down Expand Up @@ -287,23 +303,23 @@ $(SOROBAN_BUILD_DIR)/%/target/git-state.txt: $(top_srcdir)/.git/modules/src/rust
printf '%s\n' "$$state" > $@.tmp; \
if cmp -s $@.tmp $@; then rm -f $@.tmp; else mv -f $@.tmp $@; fi

# The "unified" rust build is a special non-production mode that builds all of
# The fastdev rust build is a special non-production mode that builds all of
# the rust dependencies of librust_stellar_core.a through a single cargo
# invocation, which is actually the "normal" way cargo operates, but which also
# has the negative side effect of resolving (merging) different point releases
# and pre-release minor versions across transitive dependencies, which means we
# can't control the _exact_ transitive dependencies as well as we'd like.
#
# So we only use the unified rust build for certain special cases such as
# So we only use the fastdev rust build for certain special cases such as
# testing with asan/tsan (they seem to only work well when built this way) and
# use the non-unified build (with separate .a files for each separate soroban
# version) for production builds.

if UNIFIED_RUST
if ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION

# In the unified build, we have to pass the --target flag. This actually breaks
# In the fastdev build, we have to pass the --target flag. This actually breaks
# the non-unified build, so we wind up setting LIBRUST_STELLAR_CORE separately
# in unified and non-unified builds.
# in fastdev and non-unified builds.
RUST_TARGET=$(shell rustc -vV | sed -n 's/host: //p')
LIBRUST_STELLAR_CORE=$(RUST_TARGET_DIR)/$(RUST_TARGET)/$(RUST_PROFILE_DIR)/librust_stellar_core.a

Expand All @@ -323,14 +339,13 @@ $(LIBRUST_STELLAR_CORE): $(RUST_HOST_DEPFILES) $(SRC_RUST_FILES) Makefile $(RUST
$(CARGOFLAGS_BUILDSTD) \
--package stellar-core \
--target $(RUST_TARGET) \
--features unified \
$(RUST_PROFILE_ARG) \
--locked \
--target-dir $(abspath $(RUST_TARGET_DIR)) \
$(CARGO_FEATURE_TRACY) $(CARGO_FEATURE_NEXT) $(CARGO_FEATURE_TESTUTILS)
$(CARGO_FEATURE_FASTDEV) $(CARGO_FEATURE_TRACY) $(CARGO_FEATURE_NEXT) $(CARGO_FEATURE_TESTUTILS)
ranlib $@

else # !UNIFIED_RUST
else # !ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION

# This next build command looks a little weird but it's necessary. We have to
# provide an auxiliary metadata string (using RUSTFLAGS=-Cmetadata=$*)
Expand Down Expand Up @@ -444,7 +459,7 @@ $(LIBRUST_STELLAR_CORE): $(RUST_HOST_DEPFILES) $(SRC_RUST_FILES) $(ALL_SOROBAN_L
$(ALL_SOROBAN_DEPEND_ARGS)
ranlib $@

endif # UNIFIED_RUST
endif # ENABLE_FASTDEV_UNSAFE_FOR_PRODUCTION

stellar_core_LDADD += $(LIBRUST_STELLAR_CORE) -ldl

Expand Down
24 changes: 10 additions & 14 deletions src/rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,27 +93,27 @@ tracy-client = { version = "=0.17.0", features = [
# makes it difficult to use an IDE to work on this crate since the IDE will not
# be able to resolve the hosts to anything at all. So we keep some _optional_
# copies of the host dependencies here, and allow enabling them with the
# `unified` feature here.
# `fastdev` feature here.
#
# To reiterate: the soroban-env-host-p{21,22,23}... dependency blocks listed
# here are NOT part of the default build. The default build relies on the
# versions pinned as git submodules.
#
# However, you can _manually_ switch the default build by enabling the `unified`
# However, you can _manually_ switch the default build by enabling the `fastdev`
# feature using a feature-toggle in an IDE (eg. using the VS Code "Rust Feature
# Toggler" extension), and the build system (src/Makefile.am) can be configured
# to use the `unified` feature if you configure with
# --enable-unified-rust-unsafe-for-production.
# to use the `fastdev` feature if you configure with
# --enable-fastdev-unsafe-for-production.
#
# If you do a unified build, be careful to reset any changes the IDE makes to
# If you do a fastdev build, be careful to reset any changes the IDE makes to
# Cargo.lock! The unified build will re-resolve transitive dependencies and
# unify them, perturbing the contents of the lockfile.

[dependencies.soroban-env-host-p27]
version = "=26.1.2"
git = "https://github.com/stellar/rs-soroban-env"
package = "soroban-env-host"
rev = "c0e58f94ff2983a09440cef6a54253349fd3c4db"
rev = "7fb0a840812fe8921bb48bebf7b4aa7160467ec8"
optional = true

[dependencies.soroban-env-host-p26]
Expand Down Expand Up @@ -189,15 +189,11 @@ rev = "8b04a2b7a92b96ad90c09a9151ef97aa9a04a9f8"

[features]

# Turn on the optional unified build. This is typically only useful in an IDE or when
# Turn on the optional fastdev build. This is typically only useful in an IDE or when
# orchestrated by the build system. See note above and in docs/CONTRIBUTING.md.
unified = ["dep:soroban-env-host-p21",
"dep:soroban-env-host-p22",
"dep:soroban-env-host-p23",
"dep:soroban-env-host-p24",
"dep:soroban-env-host-p25",
"dep:soroban-env-host-p26",
"dep:soroban-env-host-p27"]
fastdev = ["dep:soroban-env-host-p26",
"dep:soroban-env-host-p27",
"next"]

Comment thread
graydon marked this conversation as resolved.
tracy = ["dep:tracy-client"]

Expand Down
Loading
Loading