ctp-rs 0.3.2+ctp.6.7.11.darwin.6.7.7

Safe & idiomatic Rust bindings for CTP; cross-platform (Windows/Linux/macOS) with built-in LocalCTP support
Documentation
// Compiled on macOS only.
//
// Newer CTP releases ship the macOS market-data SDK as a .framework (a
// universal Mach-O dylib) instead of the older static archive. To preserve
// the "one self-contained binary" experience that the static .a gave us, we:
//
//   1. Embed the dylib bytes into the executable's __DATA,__const segment
//      via .incbin (see md_dylib_blob.cpp generated by build.rs). The bytes
//      live between _ctp_rs_md_dylib_start and _ctp_rs_md_dylib_end.
//
//   2. On the first call into mdapi, write those bytes to a private temp
//      file, dlopen() it, and dlsym() the two static entry points the
//      header advertises — CreateFtdcMdApi and GetApiVersion. Every other
//      method on CThostFtdcMdApi/CThostFtdcMdSpi is virtual, so once we own
//      a CThostFtdcMdApi* the rest of the wrapper calls through the vtable
//      that the dylib already populated; no dlsym is needed for those.
//
// We also bridge the 4-arg CreateFtdcMdApi declared by the linux headers we
// build the rest of the wrapper against to the 3-arg version the darwin
// dylib actually exports — bIsProductionMode has no equivalent here and is
// silently dropped.

#include "ctp-rs/wrapper/include/DarwinDylibLoader.h"

#include <cstdio>
#include <cstdlib>
#include <dlfcn.h>
#include <mutex>

extern "C" const unsigned char ctp_rs_md_dylib_start[];
extern "C" const unsigned char ctp_rs_md_dylib_end[];

namespace {

using CreateFn = void* (*)(const char*, bool, bool);
using VersionFn = const char* (*)();

CreateFn g_create = nullptr;
VersionFn g_version = nullptr;

bool ensure_loaded() {
    static std::once_flag once;
    static bool ok = false;
    std::call_once(once, [] {
        void* h = ctp_rs::darwin::extract_and_dlopen(
            "thostmduserapi_se",
            ctp_rs_md_dylib_start, ctp_rs_md_dylib_end);
        if (!h) return;

        // Itanium-mangled names for:
        //   CThostFtdcMdApi::CreateFtdcMdApi(char const*, bool, bool)
        //   CThostFtdcMdApi::GetApiVersion()
        // Verified with `nm -gU` on the shipped framework binary.
        g_create = reinterpret_cast<CreateFn>(
            ::dlsym(h, "_ZN15CThostFtdcMdApi15CreateFtdcMdApiEPKcbb"));
        g_version = reinterpret_cast<VersionFn>(
            ::dlsym(h, "_ZN15CThostFtdcMdApi13GetApiVersionEv"));
        if (!g_create || !g_version) {
            const char* err = ::dlerror();
            std::fprintf(stderr,
                "ctp-rs: dlsym mdapi entry points failed: %s\n",
                err ? err : "<no dlerror>");
            return;
        }
        ok = true;
    });
    return ok;
}

[[noreturn]] void abort_unloaded(const char* what) {
    std::fprintf(stderr,
        "ctp-rs: %s called before embedded mdapi dylib could be loaded; "
        "aborting\n",
        what);
    std::abort();
}

} // namespace

extern "C" void* CtpRsDarwinCreateFtdcMdApi(
    const char* flow_path, bool is_using_udp, bool is_multicast) {
    if (!ensure_loaded()) abort_unloaded("CreateFtdcMdApi");
    return g_create(flow_path, is_using_udp, is_multicast);
}

extern "C" const char* CtpRsDarwinGetMdApiVersion() {
    if (!ensure_loaded()) abort_unloaded("GetApiVersion");
    return g_version();
}