diff --git a/.gitignore b/.gitignore index ea7935f1..98804cd9 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,14 @@ Makefile* *.sln make +# CMake +/build*/ +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +CTestTestfile.cmake +CMakeUserPresets.json + # Artifacts *.swp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..52a5fc56 --- /dev/null +++ b/CMakeLists.txt @@ -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 + $ + $) + +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 -- 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() diff --git a/cmake/QuickFASTConfig.cmake.in b/cmake/QuickFASTConfig.cmake.in new file mode 100644 index 00000000..c4ccfcd2 --- /dev/null +++ b/cmake/QuickFASTConfig.cmake.in @@ -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) diff --git a/src/Communication/AsioCompatibility.h b/src/Communication/AsioCompatibility.h new file mode 100644 index 00000000..bbad0de6 --- /dev/null +++ b/src/Communication/AsioCompatibility.h @@ -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 preferably as a precompiled header file. +#endif //QUICKFAST_HEADERS + +#include "AsioService_fwd.h" +#include +#include + +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 + 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 diff --git a/src/Communication/AsioService.h b/src/Communication/AsioService.h index 4f619156..bd84fb76 100644 --- a/src/Communication/AsioService.h +++ b/src/Communication/AsioService.h @@ -7,7 +7,7 @@ #endif #ifndef ASIOSERVICE_H #define ASIOSERVICE_H -#include "AsioService_fwd.h" +#include "AsioCompatibility.h" #include #include #include @@ -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; } @@ -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 void post(CompletionHandler handler) { - ioService_.post(handler); + postHandler(ioService_, handler); } /// @brief Attempt to determine how many threads are available to ASIO diff --git a/src/Communication/AsioService_fwd.h b/src/Communication/AsioService_fwd.h index dc2f2354..a3f01ab7 100644 --- a/src/Communication/AsioService_fwd.h +++ b/src/Communication/AsioService_fwd.h @@ -11,6 +11,24 @@ #error Please include 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 +#if BOOST_VERSION >= 108700 +// Boost 1.87 removed the io_service name altogether. +# include +namespace boost +{ + namespace asio + { + typedef io_context io_service; + } +} +#elif BOOST_VERSION >= 106600 +# include +#else // forward declare io_service without including // boost header namespace boost @@ -20,6 +38,7 @@ namespace boost class io_service; } } +#endif // BOOST_VERSION >= 106600 namespace QuickFAST { diff --git a/src/Communication/AsynchSender.cpp b/src/Communication/AsynchSender.cpp index 0261302f..669918f3 100644 --- a/src/Communication/AsynchSender.cpp +++ b/src/Communication/AsynchSender.cpp @@ -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; } @@ -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; } diff --git a/src/Communication/AsynchSender.h b/src/Communication/AsynchSender.h index 5eb02c25..b2393c0b 100644 --- a/src/Communication/AsynchSender.h +++ b/src/Communication/AsynchSender.h @@ -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 keepAlive_; + boost::scoped_ptr keepAlive_; }; } } diff --git a/src/Communication/MulticastReceiver.h b/src/Communication/MulticastReceiver.h index cb9a9993..4aa4d423 100644 --- a/src/Communication/MulticastReceiver.h +++ b/src/Communication/MulticastReceiver.h @@ -36,10 +36,10 @@ namespace QuickFAST ) : parent_(parent) , name_(name) - , listenInterface_(boost::asio::ip::address::from_string(listenInterfaceIP)) + , listenInterface_(makeAddress(listenInterfaceIP)) , portNumber_(portNumber) - , multicastGroup_(boost::asio::ip::address::from_string(multicastGroupIP)) - , bindAddress_(boost::asio::ip::address::from_string(bindIP)) + , multicastGroup_(makeAddress(multicastGroupIP)) + , bindAddress_(makeAddress(bindIP)) , endpoint_(listenInterface_, portNumber) , socket_(ioService) , joined_(false) diff --git a/src/Communication/MulticastSender.h b/src/Communication/MulticastSender.h index f0c7be18..bcbb3f99 100644 --- a/src/Communication/MulticastSender.h +++ b/src/Communication/MulticastSender.h @@ -62,7 +62,7 @@ namespace QuickFAST ///@brief Prepare the sender to be used bool initializeSender() { - multicastAddress_ = boost::asio::ip::address::from_string(sendAddress_); + multicastAddress_ = makeAddress(sendAddress_); endpoint_ = boost::asio::ip::udp::endpoint(multicastAddress_, portNumber_); socket_.open(endpoint_.protocol()); return true; diff --git a/src/Communication/TCPReceiver.h b/src/Communication/TCPReceiver.h index 6ddb4363..8b45ebc3 100644 --- a/src/Communication/TCPReceiver.h +++ b/src/Communication/TCPReceiver.h @@ -60,12 +60,26 @@ namespace QuickFAST bool ok = true; // generate a collection of possible endpoints for this host:port boost::asio::ip::tcp::resolver resolver(ioService_); +#if BOOST_VERSION >= 106600 + // resolver::query and the iterator-returning resolve() were replaced + // in Boost 1.66 and removed in Boost 1.87. + boost::asio::ip::tcp::resolver::results_type endpoints = + resolver.resolve(hostName_, port_); + boost::asio::ip::tcp::resolver::results_type::const_iterator iterator = + endpoints.begin(); + boost::asio::ip::tcp::resolver::results_type::const_iterator endIterator = + endpoints.end(); + + // then iterate thru the collection until we find one that works. + boost::system::error_code error; +#else boost::asio::ip::tcp::resolver::query query( hostName_, port_); boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); // then iterate thru the collection until we find one that works. boost::system::error_code error; boost::asio::ip::tcp::resolver::iterator endIterator; +#endif // BOOST_VERSION >= 106600 bool connected = false; while(!connected && iterator != endIterator) { diff --git a/src/Examples/CMakeLists.txt b/src/Examples/CMakeLists.txt new file mode 100644 index 00000000..0b67e7fc --- /dev/null +++ b/src/Examples/CMakeLists.txt @@ -0,0 +1,35 @@ +# Copyright (c) 2009, 2010, 2011, Object Computing, Inc. +# All rights reserved. +# See the file license.txt for licensing information. +# +# The QuickFAST example programs (see src/Examples/Examples.mpc). + +# Code shared by all of the examples; QuickFASTExample.mpb folds these sources +# into every example program, so a static helper library is used here instead. +file(GLOB QUICKFAST_EXAMPLES_SUPPORT CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/Examples/*.cpp) + +add_library(QuickFASTExamplesSupport STATIC ${QUICKFAST_EXAMPLES_SUPPORT}) +target_include_directories(QuickFASTExamplesSupport PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(QuickFASTExamplesSupport PUBLIC QuickFAST) + +if(QUICKFAST_USE_PCH) + target_precompile_headers(QuickFASTExamplesSupport PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Examples/ExamplesPch.h) +endif() + +foreach(example + InterpretApplication + TutorialApplication + PerformanceTest + FileToTCP + FileToMulticast + PCapToMulticast) + file(GLOB ${example}_SOURCES CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/${example}/*.cpp) + add_executable(${example} ${${example}_SOURCES}) + target_link_libraries(${example} PRIVATE QuickFASTExamplesSupport) + if(QUICKFAST_USE_PCH) + target_precompile_headers(${example} REUSE_FROM QuickFASTExamplesSupport) + endif() +endforeach() diff --git a/src/Examples/FileToMulticast/FileToMulticast.cpp b/src/Examples/FileToMulticast/FileToMulticast.cpp index 4f714958..2c4e93f8 100644 --- a/src/Examples/FileToMulticast/FileToMulticast.cpp +++ b/src/Examples/FileToMulticast/FileToMulticast.cpp @@ -263,8 +263,18 @@ FileToMulticast::run() << "Largest is " << bufferSize_ << " bytes." << std::endl; } +#if BOOST_VERSION >= 106600 + // strand::wrap and strand::dispatch were replaced in Boost 1.66. + boost::asio::dispatch(strand_, boost::bind(&FileToMulticast::sendBurst, this)); +#else +#if BOOST_VERSION >= 106600 + // strand::dispatch now takes the handler itself, already bound. + boost::asio::dispatch(strand_, boost::bind(&FileToMulticast::sendBurst, this)); +#else strand_.dispatch( strand_.wrap(boost::bind(&FileToMulticast::sendBurst, this))); +#endif // BOOST_VERSION >= 106600 +#endif // BOOST_VERSION >= 106600 StopWatch lapse; this->ioService_.run(); unsigned long sendLapse = lapse.freeze(); @@ -302,9 +312,19 @@ FileToMulticast::sendBurst() // set the next timeout if(sendMicroseconds_ != 0) { +#if BOOST_VERSION >= 106600 + timer_.expires_after(std::chrono::microseconds(sendMicroseconds_)); +#else timer_.expires_from_now(boost::posix_time::microseconds(sendMicroseconds_)); +#endif // BOOST_VERSION >= 106600 timer_.async_wait( +#if BOOST_VERSION >= 106600 + // strand::wrap was replaced by bind_executor in Boost 1.66. + boost::asio::bind_executor( + strand_, boost::bind(&FileToMulticast::sendBurst, this)) +#else strand_.wrap(boost::bind(&FileToMulticast::sendBurst, this)) +#endif // BOOST_VERSION >= 106600 ); } diff --git a/src/Examples/FileToMulticast/FileToMulticast.h b/src/Examples/FileToMulticast/FileToMulticast.h index d6d62fff..60d4fab4 100644 --- a/src/Examples/FileToMulticast/FileToMulticast.h +++ b/src/Examples/FileToMulticast/FileToMulticast.h @@ -9,6 +9,7 @@ #include #include #include +#include namespace QuickFAST{ namespace Examples{ @@ -64,8 +65,16 @@ namespace QuickFAST{ bool verbose_; Communication::AsioService ioService_; - boost::asio::strand strand_; + // boost::asio::strand became a template in Boost 1.66; the class this + // example uses is spelled io_service::strand in every release. + boost::asio::io_service::strand strand_; +#if BOOST_VERSION >= 106600 + // Asio's date_time based timers became opt-in, so the example uses the + // chrono based timer that is always available. + boost::asio::steady_timer timer_; +#else boost::asio::deadline_timer timer_; +#endif // BOOST_VERSION >= 106600 Application::CommandArgParser commandArgParser_; FILE * dataFile_; diff --git a/src/Examples/FileToTCP/FileToTCP.cpp b/src/Examples/FileToTCP/FileToTCP.cpp index 9ed52088..8d2a6187 100644 --- a/src/Examples/FileToTCP/FileToTCP.cpp +++ b/src/Examples/FileToTCP/FileToTCP.cpp @@ -121,12 +121,19 @@ FileToTCP::run() for (size_t count = 0; count < sendCount_ || sendCount_ == 0; ++count) { - tcp::iostream stream; if(verbose_) { std::cout << "Listening" << std::endl; } +#if BOOST_VERSION >= 106600 + // Boost 1.66 made basic_socket a private base of the stream buffer, so + // the accepted socket is moved into the stream instead of accepted into + // the stream's buffer. + tcp::iostream stream(acceptor.accept()); +#else + tcp::iostream stream; acceptor.accept(*stream.rdbuf()); +#endif // BOOST_VERSION >= 106600 if(verbose_) { std::cout << "Accepting" << std::endl; diff --git a/src/Examples/FileToTCP/FileToTCP.h b/src/Examples/FileToTCP/FileToTCP.h index 6bca9e08..48d322bb 100644 --- a/src/Examples/FileToTCP/FileToTCP.h +++ b/src/Examples/FileToTCP/FileToTCP.h @@ -5,6 +5,7 @@ #ifndef FILETOTCP_H #define FILETOTCP_H #include +#include #include #include diff --git a/src/Examples/InterpretApplication/InterpretApplication.cpp b/src/Examples/InterpretApplication/InterpretApplication.cpp index 9e908541..2185b1d2 100644 --- a/src/Examples/InterpretApplication/InterpretApplication.cpp +++ b/src/Examples/InterpretApplication/InterpretApplication.cpp @@ -252,7 +252,7 @@ InterpretApplication::run() "r" #endif ); - if(bufferFile <= 0) + if(bufferFile == 0) { std::cerr << "Can't open file " << bufferFilename_ << std::endl; return -1; diff --git a/src/Examples/PCapToMulticast/PCapToMulticast.cpp b/src/Examples/PCapToMulticast/PCapToMulticast.cpp index c08d11f2..b58dd7d3 100644 --- a/src/Examples/PCapToMulticast/PCapToMulticast.cpp +++ b/src/Examples/PCapToMulticast/PCapToMulticast.cpp @@ -166,7 +166,7 @@ PCapToMulticast::applyArgs() } ok = ok && pcapReader_.open(dataFileName_.c_str());// for debugging dump to->, &std::cout); - multicastAddress_ = boost::asio::ip::address::from_string(sendAddress_); + multicastAddress_ = Communication::makeAddress(sendAddress_); endpoint_ = boost::asio::ip::udp::endpoint(multicastAddress_, portNumber_); socket_.open(endpoint_.protocol()); std::cout << "Opening multicast group: " << endpoint_.address().to_string() << ':' << endpoint_.port() << std::endl; @@ -189,8 +189,13 @@ PCapToMulticast::run() std::cout << " Configuring multicast: " << multicastAddress_ << '|' << sendAddress_ << ':' << portNumber_ << std::endl; } +#if BOOST_VERSION >= 106600 + // strand::dispatch now takes the handler itself, already bound. + boost::asio::dispatch(strand_, boost::bind(&PCapToMulticast::sendBurst, this)); +#else strand_.dispatch( strand_.wrap(boost::bind(&PCapToMulticast::sendBurst, this))); +#endif // BOOST_VERSION >= 106600 StopWatch lapse; this->ioService_.run(); unsigned long sendLapse = lapse.freeze(); @@ -228,9 +233,19 @@ PCapToMulticast::sendBurst() // set the next timeout if(sendMicroseconds_ != 0) { +#if BOOST_VERSION >= 106600 + timer_.expires_after(std::chrono::microseconds(sendMicroseconds_)); +#else timer_.expires_from_now(boost::posix_time::microseconds(sendMicroseconds_)); +#endif // BOOST_VERSION >= 106600 timer_.async_wait( +#if BOOST_VERSION >= 106600 + // strand::wrap was replaced by bind_executor in Boost 1.66. + boost::asio::bind_executor( + strand_, boost::bind(&PCapToMulticast::sendBurst, this)) +#else strand_.wrap(boost::bind(&PCapToMulticast::sendBurst, this)) +#endif // BOOST_VERSION >= 106600 ); } diff --git a/src/Examples/PCapToMulticast/PCapToMulticast.h b/src/Examples/PCapToMulticast/PCapToMulticast.h index fe97b25b..44038e9e 100644 --- a/src/Examples/PCapToMulticast/PCapToMulticast.h +++ b/src/Examples/PCapToMulticast/PCapToMulticast.h @@ -8,8 +8,10 @@ #define PCAP_SUPPORT_IS_HEREx #include #include +#include #include #include +#include namespace QuickFAST{ namespace Examples{ @@ -66,8 +68,16 @@ namespace QuickFAST{ boost::asio::ip::address multicastAddress_; boost::asio::ip::udp::endpoint endpoint_; boost::asio::ip::udp::socket socket_; - boost::asio::strand strand_; + // boost::asio::strand became a template in Boost 1.66; the class this + // example uses is spelled io_service::strand in every release. + boost::asio::io_service::strand strand_; +#if BOOST_VERSION >= 106600 + // Asio's date_time based timers became opt-in, so the example uses the + // chrono based timer that is always available. + boost::asio::steady_timer timer_; +#else boost::asio::deadline_timer timer_; +#endif // BOOST_VERSION >= 106600 Application::CommandArgParser commandArgParser_; // FILE * dataFile_; diff --git a/src/Tests/CMakeLists.txt b/src/Tests/CMakeLists.txt new file mode 100644 index 00000000..32832d9c --- /dev/null +++ b/src/Tests/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2009, Object Computing, Inc. +# All rights reserved. +# See the file license.txt for licensing information. +# +# The QuickFAST unit tests (see the *test project in src/QuickFAST.mpc). + +find_package(Boost REQUIRED COMPONENTS unit_test_framework filesystem system thread date_time) + +file(GLOB QUICKFAST_TEST_SOURCES CONFIGURE_DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) + +add_executable(QuickFASTTest ${QUICKFAST_TEST_SOURCES}) + +target_link_libraries(QuickFASTTest PRIVATE + QuickFAST + Boost::unit_test_framework + Boost::filesystem) + +# Boost.Test wants BOOST_TEST_DYN_LINK when it is a shared library, and must +# not have it when it is static: the definition decides whether the test +# runner's main() comes from the library or from the test binary. +get_target_property(quickfast_boost_test_type Boost::unit_test_framework TYPE) +if(quickfast_boost_test_type STREQUAL "SHARED_LIBRARY") + target_compile_definitions(QuickFASTTest PRIVATE BOOST_TEST_DYN_LINK) +endif() + +if(QUICKFAST_USE_PCH) + target_precompile_headers(QuickFASTTest PRIVATE + ${CMAKE_SOURCE_DIR}/src/Common/QuickFASTPch.h) +endif() + +add_test(NAME QuickFASTTest COMMAND QuickFASTTest) + +# Several tests locate their XML templates through $QUICKFAST_ROOT rather than +# through the working directory, so the variable is supplied to ctest here. +set_tests_properties(QuickFASTTest PROPERTIES + ENVIRONMENT QUICKFAST_ROOT=${CMAKE_SOURCE_DIR}) diff --git a/src/Tests/testPresenceMap.cpp b/src/Tests/testPresenceMap.cpp index 21139f58..50dd1d68 100644 --- a/src/Tests/testPresenceMap.cpp +++ b/src/Tests/testPresenceMap.cpp @@ -19,7 +19,7 @@ BOOST_AUTO_TEST_CASE(testPmapDecoding) BOOST_CHECK(!pmap.checkNextField()); } - uchar oneBytePMAP[] = {'\xFF'}; + uchar oneBytePMAP[] = {0xFF}; pmap.setRaw(oneBytePMAP, 1); for(size_t n = 0; n < 7; ++n) // The first 7 should be present @@ -43,7 +43,7 @@ BOOST_AUTO_TEST_CASE(testPmapDecoding) BOOST_CHECK(!pmap.checkNextField()); } - uchar everyOtherOne[] = {'\x55', '\xAA'}; + uchar everyOtherOne[] = {0x55, 0xAA}; BOOST_CHECK_EQUAL(sizeof(everyOtherOne), 2); pmap.setRaw(everyOtherOne, sizeof(everyOtherOne)); size_t ones = 0;