Modern build: Docker, vcpkg and CMake, and a build that works on current Boost - #1
Merged
Merged
Conversation
Boost 1.66 reorganized Asio and Boost 1.87 removed what it had deprecated, so QuickFAST has not compiled against a current Boost for some years. These are the changes needed to build with Boost 1.66 through at least 1.91, with every replacement selected on BOOST_VERSION so that older Boost releases build exactly as they did before. The library: * AsioService_fwd.h forward declared boost::asio::io_service as a class. From Boost 1.66 on it is a typedef for io_context, so that declaration conflicts with Asio's own and every use of the type fails. The name is now taken from Asio itself; Boost 1.87 and later, which dropped the name entirely, get a typedef for io_context. * The Asio I/O objects replaced their io_service& constructors with a template that asks its argument for an executor, so the implicit cast on AsioService is no longer enough to construct a socket or a resolver from one. AsioService now forwards get_executor() to the io_service it wraps. * A new header, Communication/AsioCompatibility.h, spells the four remaining interfaces the way the Boost release being compiled against expects: ip::address::from_string is now make_address, io_service::post is now the free function post, io_service::reset is now restart, and io_service::work is now executor_work_guard. The call sites ask it rather than repeating a version test each time. * The iterator-returning resolver::resolve(query) in TCPReceiver became resolve(host, service) returning a results range. The examples: * boost::asio::strand became a template, so the two burst senders name the class they want, io_service::strand, and reach it through dispatch and bind_executor rather than the strand's own wrap and dispatch. * Asio's date_time based timers are opt-in in recent releases, so those two examples use steady_timer and a chrono duration instead of deadline_timer and a posix_time duration. * basic_socket became a private base of the socket stream buffer, so FileToTCP moves an accepted socket into its stream instead of accepting into the stream's buffer. * Compare the FILE* returned by std::fopen against 0 rather than ordering it against 0, which gcc rejects. Verified on Ubuntu 24.04 (gcc 13, Boost 1.83), Ubuntu 25.10 (gcc 15, Boost 1.88) and against Boost 1.91 built by vcpkg: the library, all six example programs and all 112 unit test cases build and pass in each. No MPC file, setup script or build flag is changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
testPresenceMap initializes arrays of uchar from char literals. Where char is signed -- x86 and x86_64, as opposed to ARM -- '\xFF' is -1, and C++11 made that a narrowing conversion inside a braced initializer, so gcc and clang reject it. Writing the bytes as integer literals says what was meant and is correct on either sign of char. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
QuickFAST is built with MPC, which asks the user to install MPC itself and to point setup.sh or setup.cmd at a Boost and a Xerces-C tree by hand. This adds a CMake build alongside it for people who would rather let find_package locate the dependencies, and so that QuickFAST can be consumed by the many projects that expect a CMake package. Nothing about the MPC build changes: no .mpc, .mpb, .mwc, .features or setup script is touched, and both builds work from the same working copy. The library target collects the same five directories the MPC project does (Application, Codecs, Common, Communication, Messages) and globs them for the same reason MPC lists directories rather than files, so that the two builds do not drift apart as sources are added. The definitions that src/Common/QuickFAST_Export.h expects are supplied for shared and for static builds, and the precompiled header the MPC build uses is kept. Tests and examples are off by default: cmake -S . -B build -DQUICKFAST_BUILD_TESTS=ON -DQUICKFAST_BUILD_EXAMPLES=ON cmake --build build ctest --test-dir build --output-on-failure The unit tests find their XML templates through $QUICKFAST_ROOT, so ctest sets it for them. Installing exports a QuickFAST::QuickFAST target, letting a downstream project build against QuickFAST with nothing more than: find_package(QuickFAST REQUIRED) target_link_libraries(app PRIVATE QuickFAST::QuickFAST) Headers install under include/QuickFAST so that the include style used throughout the sources -- #include <Codecs/Decoder.h> -- keeps working without putting directories named Common or Messages on a consumer's include path. Verified on Ubuntu 24.04 (gcc 13, Boost 1.83, Xerces-C 3.2) and Ubuntu 25.10 (gcc 15, Boost 1.88): static and shared builds, all 112 unit test cases, all six examples, and a separate consumer project built against the installed package. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
Boost and Xerces-C still have to be installed before QuickFAST can be built. This adds a vcpkg manifest so that vcpkg can build them instead, pinned to a baseline so the result does not change when Boost publishes a new release, and a presets file so that neither route needs a command line full of cache variables: cmake --preset default # Boost and Xerces-C from the platform cmake --preset vcpkg # Boost and Xerces-C built by vcpkg The manifest lists the Boost modules the sources actually include rather than depending on Boost as a whole. Boost.Test and Boost.Filesystem, which only the unit tests use, are behind a "tests" feature. Neither file affects a build that does not ask for it: without --preset and without the vcpkg toolchain, find_package looks where it always did. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
Builds QuickFAST, runs the unit tests and keeps the example programs in a small runtime image, so that the project can be built and tried without installing a toolchain, Boost or Xerces-C on the host: docker build -t quickfast . docker run --rm quickfast -? Dependencies come from vcpkg at the baseline pinned in vcpkg.json. Building Boost from source is slow, so the downloads and the built packages are kept in BuildKit cache mounts; after the first build only QuickFAST itself is recompiled. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
MagnaibayarMN
force-pushed
the
modern-build
branch
from
September 12, 2026 01:57
2ebbf16 to
32f8796
Compare
The repository has no automated build, so a change that breaks one platform is only found when someone happens to build there. This workflow builds and tests QuickFAST on Linux with gcc and clang, on macOS and on Windows with MSVC, builds the Docker image and runs it, and builds a small consuming project against the installed CMake package so that the export stays usable. The last job regenerates the MPC makefiles. The CMake build is an addition, not a replacement, and this keeps the MPC project files from quietly rotting. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
Gives an editor that understands dev containers a ready toolchain: a C++ compiler, CMake, Ninja, gdb, perl for the MPC build, and vcpkg at the baseline pinned in vcpkg.json. QUICKFAST_ROOT is set for the unit tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
The getting started wiki page assumes MPC and a hand-edited setup script. This documents the CMake, vcpkg and Docker routes alongside it, so that the first thing a reader finds is a build that works without any setup. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF
MagnaibayarMN
force-pushed
the
modern-build
branch
from
September 12, 2026 02:09
32f8796 to
182d385
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Makes QuickFAST buildable again on a machine bought this decade, and turns "get QuickFAST compiling" from a day of archaeology into one command.
That is the whole setup. No MPC, no Boost, no Xerces-C, no environment variables, nothing installed on the host.
The problem this solves
QuickFAST's build instructions have not moved since 2017, and they were already pointing at the past then.
setup.shstill defaults to this:So a newcomer has three ways to go, and until now all three ended badly:
Use the Boost your distribution ships. Every current distribution is on Boost 1.74 or later. The build dies immediately:
followed by a few hundred cascading errors. Nothing in the error text suggests the cause, and the cause is one line in
AsioService_fwd.hthat forward declares an Asio type Asio itself has redefined.Build the Boost that
setup.shnames. Boost 1.38 is from 2009 and does not compile with a current gcc or clang. Neither does Xerces-C 3.0.1. You are now debugging two dependencies before you have compiled a line of QuickFAST.Find some Boost in between. There is a narrow window that works — and finding it means bisecting sixteen years of Boost releases, because Asio changed in at least four distinct ways over that span:
io_servicebecame a typedef; QuickFAST's forward declaration conflicts with itio_servicename is gone entirely, along withwork,resolver::queryandfrom_stringdeadline_timerdisappears tooAnd that is only Boost. Xerces-C moved from 3.0 to 3.2, so the library name
setup.shexports is wrong as well, and MPC itself is a separate tool that has to be fetched and put on$PATHbefore any of this starts.The result is that a library which is genuinely useful — a mature, fast, permissively licensed FAST decoder — is effectively unavailable to anyone who is not willing to spend a day on it. That is the barrier this PR removes.
What it does
Seven commits, each self-contained:
1. Build against current Boost releases. The actual source fixes, every one of them selected on
BOOST_VERSIONso that older Boost builds exactly as it did before. The root cause is the forward declaration described above; the rest follows from it —AsioServicenow offers theget_executor()that Asio's I/O objects ask for, and a new header,Communication/AsioCompatibility.h, spellsmake_address,post,restartandexecutor_work_guardthe way the Boost being compiled against expects, so the call sites do not each carry a version test.TCPReceiveruses the results-range form ofresolve, and the two burst-sender examples usesteady_timerandbind_executor. Verified against Boost 1.83, 1.88 and 1.91.2. An optional CMake build.
find_packagelocates Boost and Xerces-C instead of a hand-edited script naming absolute paths. Installing exports a target, so a downstream project needs two lines:3. A vcpkg manifest and CMake presets. This is what makes the build reproducible rather than merely possible. The manifest pins a vcpkg baseline by commit, so
cmake --preset vcpkgbuilds against one exact Boost and one exact Xerces-C — the same ones on your laptop, on CI, and in two years' time. Version drift stops being something you manage and starts being something recorded in a file.4. A Dockerfile. Multi-stage: vcpkg pinned to that same baseline builds the dependencies, QuickFAST and its tests are built and run, and the example programs land in a 121 MB runtime image. Boost from source is slow, so the vcpkg downloads and built packages live in BuildKit cache mounts — after the first build only QuickFAST itself recompiles.
5. A GitHub Actions workflow. Linux with gcc and clang, macOS, Windows with MSVC, the Docker image, and a small project built against the installed CMake package. One job regenerates the MPC makefiles, so the original build cannot rot unnoticed.
6. A development container. The toolchain, vcpkg and gdb, ready for an editor that understands dev containers.
7. README build instructions. CMake, vcpkg, Docker and MPC, side by side.
What it does not do
The MPC build is untouched. No
.mpc,.mpb,.mwc,.featuresor setup script is modified. Both builds work from the same working copy, and CI checks that the MPC project files still generate. This is an addition, not a migration — anyone with a working MPC setup keeps it.Verification
Every claim above was built and run, not assumed:
Also checked: static and shared library builds,
cmake --installfollowed by a separate consumer project linkingQuickFAST::QuickFAST, anddocker run --rm quickfastproducingInterpretApplication's usage output.The macOS and Windows CI jobs have not run yet — this PR is the first time they will.
Upstream
The two commits that matter most to everyone else are already proposed to the original project:
The remaining five are held back deliberately: that repository has not seen a commit since March 2017, and seven simultaneous pull requests would bury a maintainer rather than help one. If those two land, the rest follow.
🤖 Generated with Claude Code
https://claude.ai/code/session_017BnyHwonMsq7k6uQxWpVGF