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
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ Makefile*
*.sln
make

# CMake
/build*/
CMakeCache.txt
CMakeFiles/
cmake_install.cmake
CTestTestfile.cmake
CMakeUserPresets.json

# Artifacts
*.swp

Expand Down
167 changes: 167 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Copyright (c) 2009, Object Computing, Inc.
# All rights reserved.
# See the file license.txt for licensing information.
#
# Optional CMake build for QuickFAST.
#
# This is an *addition* to the existing MPC build, not a replacement: no MPC
# file, setup script or source file is modified by this build system, and both
# builds can be used side by side from the same working copy.
#
# Quick start:
# cmake -S . -B build -DQUICKFAST_BUILD_TESTS=ON
# cmake --build build
# ctest --test-dir build --output-on-failure
#
# Boost and Xerces-C are located with find_package, so they can come from the
# platform packages, from a local build or from a package manager.

cmake_minimum_required(VERSION 3.16)

project(QuickFAST
VERSION 1.5.0
DESCRIPTION "An implementation of the FAST protocol for native C++"
HOMEPAGE_URL "https://github.com/objectcomputing/quickfast"
LANGUAGES CXX)

include(GNUInstallDirs)
include(CMakePackageConfigHelpers)

option(QUICKFAST_BUILD_TESTS "Build the QuickFAST unit tests" OFF)
option(QUICKFAST_BUILD_EXAMPLES "Build the QuickFAST example programs" OFF)
option(QUICKFAST_USE_PCH "Use a precompiled header (mirrors the MPC build)" ON)

# QuickFAST predates C++11. C++11 is the lowest standard that current Boost
# releases support, so it is used as the floor rather than the compiler default.
if(NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
endif()

# CMake 3.30 removed its own FindBoost in favour of the config file Boost
# itself installs. Ask for that behaviour where the policy exists.
if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW)
endif()

find_package(Boost REQUIRED COMPONENTS system thread date_time)
find_package(XercesC REQUIRED)

# ---------------------------------------------------------------------------
# The QuickFAST library
#
# The MPC build collects whole directories (see src/QuickFAST.mpc), so globbing
# is used here to keep the two builds from drifting apart when files are added.
# ---------------------------------------------------------------------------
file(GLOB_RECURSE QUICKFAST_SOURCES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/src/Application/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Codecs/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Common/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Communication/*.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Messages/*.cpp)

file(GLOB_RECURSE QUICKFAST_HEADERS CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/src/Application/*.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Codecs/*.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Common/*.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Communication/*.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Messages/*.h)

add_library(QuickFAST ${QUICKFAST_SOURCES} ${QUICKFAST_HEADERS})
add_library(QuickFAST::QuickFAST ALIAS QuickFAST)

target_include_directories(QuickFAST PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/QuickFAST>)

target_link_libraries(QuickFAST PUBLIC
Boost::system
Boost::thread
Boost::date_time
XercesC::XercesC)

set_target_properties(QuickFAST PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
OUTPUT_NAME QuickFAST)

# src/Common/QuickFAST_Export.h decides between dllexport, dllimport and
# nothing. These definitions give it the same answers the MPC build does.
if(BUILD_SHARED_LIBS)
target_compile_definitions(QuickFAST PRIVATE QUICKFAST_BUILD_DLL)
else()
target_compile_definitions(QuickFAST PUBLIC QUICKFAST_HAS_DLL=0)
endif()

if(MSVC)
target_compile_definitions(QuickFAST PUBLIC
BOOST_DATE_TIME_NO_LIB
BOOST_REGEX_NO_LIB
_WIN32_WINNT=0x0601)
# QuickFAST predates several of the warnings current MSVC emits; the
# precompiled header already disables the ones the authors reviewed.
target_compile_options(QuickFAST PRIVATE /wd4267 /wd4244)
else()
# FieldInstructionInteger generates spurious warnings based on
# signed/unsigned template arguments (see QuickFASTApplication.mpb).
target_compile_options(QuickFAST PRIVATE -Wtype-limits)
endif()

if(QUICKFAST_USE_PCH)
target_precompile_headers(QuickFAST PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/Common/QuickFASTPch.h)
endif()

# ---------------------------------------------------------------------------
# Installation and the QuickFASTConfig.cmake package
# ---------------------------------------------------------------------------
install(TARGETS QuickFAST
EXPORT QuickFASTTargets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Headers are installed under a QuickFAST/ prefix 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.
foreach(module Application Codecs Common Communication Messages)
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/src/${module}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/QuickFAST
FILES_MATCHING PATTERN "*.h")
endforeach()

install(EXPORT QuickFASTTargets
FILE QuickFASTTargets.cmake
NAMESPACE QuickFAST::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/QuickFAST)

configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/QuickFASTConfig.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/QuickFASTConfig.cmake
INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/QuickFAST)

write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/QuickFASTConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion)

install(FILES
${CMAKE_CURRENT_BINARY_DIR}/QuickFASTConfig.cmake
${CMAKE_CURRENT_BINARY_DIR}/QuickFASTConfigVersion.cmake
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/QuickFAST)

# ---------------------------------------------------------------------------
# Optional components
# ---------------------------------------------------------------------------
if(QUICKFAST_BUILD_TESTS)
enable_testing()
add_subdirectory(src/Tests)
endif()

if(QUICKFAST_BUILD_EXAMPLES)
add_subdirectory(src/Examples)
endif()
13 changes: 13 additions & 0 deletions cmake/QuickFASTConfig.cmake.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright (c) 2009, Object Computing, Inc.
# All rights reserved.
# See the file license.txt for licensing information.
@PACKAGE_INIT@

include(CMakeFindDependencyMacro)

find_dependency(Boost COMPONENTS system thread date_time)
find_dependency(XercesC)

include("${CMAKE_CURRENT_LIST_DIR}/QuickFASTTargets.cmake")

check_required_components(QuickFAST)
88 changes: 88 additions & 0 deletions src/Communication/AsioCompatibility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright (c) 2009, 2010, 2011 Object Computing, Inc.
// All rights reserved.
// See the file license.txt for licensing information.
//
#ifdef _MSC_VER
# pragma once
#endif
#ifndef ASIOCOMPATIBILITY_H
#define ASIOCOMPATIBILITY_H
#ifndef QUICKFAST_HEADERS
#error Please include <Application/QuickFAST.h> preferably as a precompiled header file.
#endif //QUICKFAST_HEADERS

#include "AsioService_fwd.h"
#include <boost/version.hpp>
#include <boost/asio.hpp>

namespace QuickFAST
{
namespace Communication
{
// Boost 1.66 replaced several of the Asio interfaces QuickFAST is written
// against, and Boost 1.87 removed the originals. Each helper below spells
// its operation the way the Boost release being compiled against expects,
// so that the call sites do not have to.

/// @brief Convert a dotted IP address to an asio address
/// @param address is the address in dotted notation
inline boost::asio::ip::address makeAddress(const std::string & address)
{
#if BOOST_VERSION >= 106600
return boost::asio::ip::make_address(address);
#else
return boost::asio::ip::address::from_string(address);
#endif
}

/// @brief Post a completion handler to an io service
/// @param ioService is the service that will run the handler
/// @param handler is the handler to be posted
template<typename CompletionHandler>
inline void postHandler(
boost::asio::io_service & ioService,
CompletionHandler handler)
{
#if BOOST_VERSION >= 106600
boost::asio::post(ioService, handler);
#else
ioService.post(handler);
#endif
}

/// @brief Keeps an io service running while it has no work to do
///
/// io_service::work was replaced by executor_work_guard in Boost 1.66 and
/// removed in Boost 1.87.
#if BOOST_VERSION >= 106600
typedef boost::asio::executor_work_guard<
boost::asio::io_context::executor_type> WorkGuard;
#else
typedef boost::asio::io_service::work WorkGuard;
#endif

/// @brief Create a work guard for an io service
/// @param ioService is the service to be kept alive
/// @returns a new work guard; the caller owns it
inline WorkGuard * makeWorkGuard(boost::asio::io_service & ioService)
{
#if BOOST_VERSION >= 106600
return new WorkGuard(boost::asio::make_work_guard(ioService));
#else
return new WorkGuard(ioService);
#endif
}

/// @brief Prepare an io service to be run again after it has stopped
/// @param ioService is the service to be restarted
inline void restartService(boost::asio::io_service & ioService)
{
#if BOOST_VERSION >= 106600
ioService.restart();
#else
ioService.reset();
#endif
}
}
}
#endif // ASIOCOMPATIBILITY_H
20 changes: 17 additions & 3 deletions src/Communication/AsioService.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#endif
#ifndef ASIOSERVICE_H
#define ASIOSERVICE_H
#include "AsioService_fwd.h"
#include "AsioCompatibility.h"
#include <Common/QuickFAST_Export.h>
#include <Common/Logger_fwd.h>
#include <Common/AtomicCounter.h>
Expand Down Expand Up @@ -87,7 +87,7 @@ namespace QuickFAST
/// should be called after joinThreads before calling run*, poll*, etc. again.
void resetService()
{
ioService_.reset();
restartService(ioService_);
stopping_ = false;
}

Expand All @@ -100,12 +100,26 @@ namespace QuickFAST
return ioService_;
}

#if BOOST_VERSION >= 106600
/// @brief the executor of the underlying io_service
///
/// Boost 1.66 replaced the io_service& constructors of the Asio I/O
/// objects with a template that asks its argument for an executor. The
/// implicit cast above is no longer enough for an AsioService to be
/// passed where an io_service used to be accepted, so the question is
/// forwarded to the io_service being wrapped.
boost::asio::io_context::executor_type get_executor()
{
return ioService_.get_executor();
}
#endif // BOOST_VERSION >= 106600

///@brief Post a completion handler for later processing (usually in a different thread)
/// @param handler is the handler to be posted
template<typename CompletionHandler>
void post(CompletionHandler handler)
{
ioService_.post(handler);
postHandler(ioService_, handler);
}

/// @brief Attempt to determine how many threads are available to ASIO
Expand Down
19 changes: 19 additions & 0 deletions src/Communication/AsioService_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,24 @@
#error Please include <Application/QuickFAST.h> preferably as a precompiled header file.
#endif //QUICKFAST_HEADERS

// Boost 1.66 turned io_service into a typedef for io_context, so the class
// declaration QuickFAST used to make here now conflicts with the one Asio
// provides. From that release on, take the declaration from Boost itself;
// io_service.hpp only pulls in io_context, not all of Asio.
#include <boost/version.hpp>
#if BOOST_VERSION >= 108700
// Boost 1.87 removed the io_service name altogether.
# include <boost/asio/io_context.hpp>
namespace boost
{
namespace asio
{
typedef io_context io_service;
}
}
#elif BOOST_VERSION >= 106600
# include <boost/asio/io_service.hpp>
#else
// forward declare io_service without including
// boost header
namespace boost
Expand All @@ -20,6 +38,7 @@ namespace boost
class io_service;
}
}
#endif // BOOST_VERSION >= 106600

namespace QuickFAST
{
Expand Down
4 changes: 2 additions & 2 deletions src/Communication/AsynchSender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ AsynchSender::AsynchSender(
: Sender(recycler)
, name_(name)
, ioService_()
, keepAlive_(new boost::asio::io_service::work(ioService_))
, keepAlive_(makeWorkGuard(ioService_))
{
//std::cout << "Asynch Sender {" << (void *)this << "} keeping ioService " << (void*) &ioService_ << " alive." << std::endl;
}
Expand All @@ -27,7 +27,7 @@ AsynchSender::AsynchSender(
: Sender(recycler)
, name_(name)
, ioService_(ioService)
, keepAlive_(new boost::asio::io_service::work(ioService_))
, keepAlive_(makeWorkGuard(ioService_))
{
// std::cout << "Asynch Sender {" << (void *)this << "} keeping shared ioService " << (void*) &ioService_ << " alive." << std::endl;
}
Expand Down
2 changes: 1 addition & 1 deletion src/Communication/AsynchSender.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ namespace QuickFAST
/// needed for output-type service which may have nothing to write at the moment, unlike
/// input-type services which should always have an outstanding read or an active handler
/// callback.
boost::scoped_ptr<boost::asio::io_service::work> keepAlive_;
boost::scoped_ptr<WorkGuard> keepAlive_;
};
}
}
Expand Down
Loading