You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

独立版ASIO与Boost ASIO的HANDLER_TRACKING兼容性问题

独立版ASIO启用Handler Tracking编译失败

问题描述

运行handler_tracking相关的async_tcp_echo_server示例时,Boost版本的ASIO可正常运行并向stderr输出追踪信息,但独立版ASIO编译失败,出现大量asio::detail::handler_tracking::location构造/析构函数的未定义引用,且未使用自定义追踪功能。

复现环境与代码

CMake配置

cmake_minimum_required(VERSION 3.23)
project(ASIO_Handler_standalone LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(CPM_DOWNLOAD_VERSION 0.42.0)
set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")

if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
    message(STATUS "Downloading CPM.cmake")
    file(DOWNLOAD https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION})
endif()

include(${CPM_DOWNLOAD_LOCATION})

find_library(LIBPTHREAD pthread)

# ASIO - standalone with threads
set(ASIO_SEPARATE_COMPILATION  ON)
set(ASIO_DYN_LINK  ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)

CPMAddPackage(
  NAME asiocmake
  GIT_REPOSITORY "https://github.com/OlivierLDff/asio.cmake"
  GIT_TAG "main"
)

add_executable(foo main.cpp)
target_link_libraries(foo asio::asio)

示例代码(main.cpp)

已在包含asio.hpp前定义ASIO_ENABLE_HANDLER_TRACKING:

//
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#define ASIO_ENABLE_HANDLER_TRACKING

#include <cstdlib>
#include <iostream>
#include <memory>
#include <utility>
#include <asio.hpp>

using asio::ip::tcp;

// Define a helper macro to invoke ASIO_HANDLER_LOCATION with the current
// file name, line number, and function name. For the function name, you might
// also consider using __PRETTY_FUNCTION__, BOOST_CURRENT_FUNCTION, or a hand-
// crafted name. For C++20 or later, you may also use std::source_location.
#define HANDLER_LOCATION \
ASIO_HANDLER_LOCATION((__FILE__, __LINE__, __func__))

class session
    : public std::enable_shared_from_this<session>
{
public:
    session(tcp::socket socket)
        : socket_(std::move(socket))
    {
    }

    void start()
    {
        HANDLER_LOCATION;

        do_read();
    }

private:
    void do_read()
    {
        HANDLER_LOCATION;

        auto self(shared_from_this());
        socket_.async_read_some(asio::buffer(data_, max_length),
                                [this, self](std::error_code ec, std::size_t length)
                                {
                                    HANDLER_LOCATION;

                                    if (!ec)
                                    {
                                        do_write(length);
                                    }
                                });
    }

    void do_write(std::size_t length)
    {
        HANDLER_LOCATION;

        auto self(shared_from_this());
        asio::async_write(socket_, asio::buffer(data_, length),
                          [this, self](std::error_code ec, std::size_t /*length*/)
                          {
                              HANDLER_LOCATION;

                              if (!ec)
                              {
                                  do_read();
                              }
                          });
    }

    tcp::socket socket_;
    enum { max_length = 1024 };
    char data_[max_length];
};

class server
{
public:
    server(asio::io_context& io_context, short port)
        : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
    {
        do_accept();
    }

private:
    void do_accept()
    {
        HANDLER_LOCATION;

        acceptor_.async_accept(
            [this](std::error_code ec, tcp::socket socket)
            {
                HANDLER_LOCATION;

                if (!ec)
                {
                    std::make_shared<session>(std::move(socket))->start();
                }

                do_accept();
            });
    }

    tcp::acceptor acceptor_;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 2)
        {
            std::cerr << "Usage: async_tcp_echo_server <port>\n";
            return 1;
        }

        asio::io_context io_context;

        server s(io_context, std::atoi(argv[1]));

        io_context.run();
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

编译错误信息

handler_tracking/standalone/main.cpp:39: error: undefined reference to `asio::detail::handler_tracking::location::location(char const*, int, char const*)'
....

(注:存在大量类似的asio::detail::handler_tracking::location构造/析构函数未定义引用错误)

解决方案

问题根源是:独立版ASIO默认未编译handler_tracking相关代码,而项目中启用ASIO_ENABLE_HANDLER_TRACKING后,编译器会尝试引用这些未实现的函数,导致链接错误。

具体修正步骤

在使用CPM添加ASIO库前,增加配置传递启用宏:

// ... 其他配置不变 ...

# ASIO - standalone with threads
set(ASIO_SEPARATE_COMPILATION  ON)
set(ASIO_DYN_LINK  ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# 新增:传递handler_tracking启用宏给ASIO库编译流程
set(ASIO_OPTIONS ASIO_ENABLE_HANDLER_TRACKING)

CPMAddPackage(
  NAME asiocmake
  GIT_REPOSITORY "https://github.com/OlivierLDff/asio.cmake"
  GIT_TAG "main"
)

// ... 其他配置不变 ...

原理说明

Boost版本的ASIO默认包含了handler_tracking的编译支持,而独立版ASIO通过asio.cmake引入时,默认不会启用该宏。通过ASIO_OPTIONS传递宏参数,让ASIO库在编译时生成handler_tracking相关代码,即可解决链接时的未定义引用问题。


内容的提问来源于stack exchange,提问作者ArchNemSyS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.11 20:13:10