This is an automated email from the ASF dual-hosted git repository.

wasphin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brpc.git


The following commit(s) were added to refs/heads/master by this push:
     new 9b0f9454 Refactor CMake source and target ownership into module 
directories (#3618)
9b0f9454 is described below

commit 9b0f9454209d05d863d9ae41980f4bc9c7654c72
Author: Xiaofeng Wang <[email protected]>
AuthorDate: Tue Oct 20 13:29:53 2026 +0800

    Refactor CMake source and target ownership into module directories (#3618)
    
    * Move CMake source definitions into module directories
    
    Keep source selection and bundled artifacts unchanged while moving each
    module source list and RPC protocol generation out of the root project.
    Retain the existing test source inputs during this first migration step.
    
    * Define CMake production targets in their module directories
    
    Let each module own its production object library and move the mcpack
    protoc generator into its module. Aggregate the module objects into the
    existing brpc bundle without compiling production sources twice.
    
    Move butil configuration-header generation, feature-option handling and
    dependency discovery into the owning modules. Keep RPC-only headers out
    of lower-library compile settings and assemble legacy bundle dependencies
    after module setup.
    
    Apply CRC32C instruction flags only to the relevant sources, including
    debug builds. Preserve the RISC-V vector base64 options and the existing
    AArch64 libcontext workaround.
    
    Query module targets for the existing unit-test source sets instead of
    passing source lists through parent directory scopes. Preserve the test
    compile definitions and bundled debug library linkage.
    
    Install source and generated headers directly from their owning modules.
    Keep build-tree include paths separate from installed target interfaces
    instead of copying headers into an output staging tree.
    
    Use Protobuf's imported targets to preserve static transitive dependencies
    and Debug/Release library selection, and handle config-mode import paths.
    
    * Use explicit installation prefixes for CMake examples
    
    Stop searching for the removed output/include staging directory and honor
    the caller-provided CMAKE_PREFIX_PATH in both example entry points.
    Document the install-before-use workflow in English and Chinese.
    
    Link Protobuf through its imported target so non-system installations
    supply the headers required by generated sources and public RPC headers.
    
    * Align the ubring example CMake minimum with the project
    
    Require CMake 3.16 and use the same policy range as the root project and
    other examples. This makes the declared minimum consistent with use of
    the protobuf::libprotobuf imported target introduced in CMake 3.9.
    
    * Configure the install prefix before generating pkg-config metadata
    
    Set CMAKE_INSTALL_PREFIX during configuration in both getting-started
    guides, then build and install without an install-time prefix override.
    This keeps the generated brpc.pc paths aligned with the installed files.
    
    * Prefer generated IDL headers when building the mcpack generator
    
    Inherit build settings through the selected brpc bundle instead of linking
    butil_build_config first. This keeps the generated IDL header directory
    ahead of the source tree and prevents stale Make-generated headers from
    shadowing the current CMake output.
    
    * Remove unused CMake module configuration leftovers
    
    Drop the unread platform-library property and unused URMA parent-scope
    exports. Remove redundant debug-bundle glog blocks, since module-owned
    bundle dependencies already propagate the library through DYNAMIC_LIB.
    
    * Document installed-prefix builds for UBRing examples
    
    Set the brpc installation prefix at configure time, install the bundle,
    and pass the prefix explicitly when building the performance example.
    Update both build sections in the English and Chinese UBRing guides.
    
    * Preserve ordered transitive dependencies for CMake bundles
    
    Propagate the complete link dependency closure from the static bundle and
    reuse it in tools rather than masking missing dependencies at each caller.
    Order module consumers before providers in both CMake and pkg-config, and
    keep system libraries after their users.
    
    Retain LevelDB Snappy dependencies independently of WITH_SNAPPY without
    exposing unused Snappy headers. Include selected optional runtime libraries
    in the generated private link metadata.
    
    Add bundle-only consumers and dependency-metadata checks to the existing
    CMake CI jobs without increasing job concurrency.
    
    * Normalize legacy LevelDB CMake target dependencies
    
    Use LevelDB's exported target to carry its link dependencies while keeping
    header and library discovery for installations without a CMake package.
    
    Work around private warning flags and unnecessary shared-library Snappy
    linkage exported by LevelDB 1.23. Preserve static and unknown-type link
    dependencies, along with brpc's explicit WITH_SNAPPY option.
    
    Give debug sources the same LevelDB requirements and add a standalone
    consumer to the existing CMake link checks without adding CI jobs.
---
 .github/workflows/ci-linux.yml                     |   1 +
 .github/workflows/ci-macos.yml                     |   8 +-
 CMakeLists.txt                                     | 575 +--------------------
 cmake/CompileProto.cmake                           |   4 +-
 cmake/SetupGtest.cmake                             |   2 +-
 cmake/bRPCHeaders.cmake                            |  37 ++
 docs/cn/getting_started.md                         |  10 +-
 docs/cn/ubring.md                                  |  12 +-
 docs/en/getting_started.md                         |  12 +-
 docs/en/ubring.md                                  |  12 +-
 example/cmake/BrpcExample.cmake                    |  12 +-
 example/dynamic_partition_echo_c++/CMakeLists.txt  |   2 +-
 example/http_c++/CMakeLists.txt                    |   4 +-
 example/multi_threaded_echo_c++/CMakeLists.txt     |   4 +-
 example/partition_echo_c++/CMakeLists.txt          |   2 +-
 example/ubring_performance/CMakeLists.txt          |  11 +-
 src/CMakeLists.txt                                 | 114 ++--
 src/brpc/CMakeLists.txt                            | 345 +++++++++++++
 src/bthread/CMakeLists.txt                         |  73 +++
 src/butil/CMakeLists.txt                           | 298 +++++++++++
 config.h.in => src/butil/config.h.in               |   0
 {tools/trackme_server => src/bvar}/CMakeLists.txt  |  10 +-
 .../trackme_server => src/json2pb}/CMakeLists.txt  |  10 +-
 src/mcpack2pb/CMakeLists.txt                       |  50 ++
 test/CMakeLists.txt                                | 271 +++++-----
 test/cmake_link_dependencies/CMakeLists.txt        |  37 ++
 test/cmake_link_dependencies/check_pkgconfig.cmake |  72 +++
 test/cmake_link_dependencies/consumer.cpp          |  43 ++
 test/cmake_link_dependencies/leveldb.cpp           |  25 +
 test/cmake_link_dependencies/logging.cpp           |  23 +
 tools/parallel_http/CMakeLists.txt                 |   2 +-
 tools/rpc_press/CMakeLists.txt                     |   4 +-
 tools/rpc_replay/CMakeLists.txt                    |   4 +-
 tools/rpc_view/CMakeLists.txt                      |   2 +-
 tools/trackme_server/CMakeLists.txt                |   2 +-
 35 files changed, 1287 insertions(+), 806 deletions(-)

diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml
index fa136970..341c53d3 100644
--- a/.github/workflows/ci-linux.yml
+++ b/.github/workflows/ci-linux.yml
@@ -114,6 +114,7 @@ jobs:
         cmake -S . -B build -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
           "${cmake_options[@]}"
         cmake --build build -j ${{env.proc_num}}
+        cmake --build build --target cmake_link_checks -j ${{env.proc_num}}
 
     - name: Show ccache statistics
       if: always()
diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml
index 0b595e27..fc4bf632 100644
--- a/.github/workflows/ci-macos.yml
+++ b/.github/workflows/ci-macos.yml
@@ -42,7 +42,9 @@ jobs:
       run: |
         echo "CMAKE_PREFIX_PATH=$(brew --prefix protobuf@21)"
         mkdir build && cd build && cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 
-DWITH_UBRING=ON -DCMAKE_PREFIX_PATH=$(brew --prefix protobuf@21) ..
-        make -j ${{env.proc_num}} && make clean
+        make -j ${{env.proc_num}}
+        cmake --build . --target cmake_link_checks -j ${{env.proc_num}}
+        make clean
 
     - name: Show ccache statistics
       if: always()
@@ -71,7 +73,9 @@ jobs:
       - name: compile with cmake
         run: |
           mkdir build && cd build && cmake -DCMAKE_POLICY_VERSION_MINIMUM=3.5 
-DWITH_UBRING=ON -DCMAKE_PREFIX_PATH=$(brew --prefix protobuf@29) ..
-          make -j ${{env.proc_num}} && make clean
+          make -j ${{env.proc_num}}
+          cmake --build . --target cmake_link_checks -j ${{env.proc_num}}
+          make clean
 
       - name: Show ccache statistics
         if: always()
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4d00c90b..59acdfe3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -71,104 +71,29 @@ endif()
 set(BRPC_COMMON_COMPILE_OPTIONS)
 set(BRPC_COMMON_DEFINITIONS)
 set(BRPC_COMMON_INCLUDE_DIRS
-    ${PROJECT_SOURCE_DIR}/src
+    ${CMAKE_CURRENT_SOURCE_DIR}/src
 )
 set(BRPC_COMMON_LINK_OPTIONS)
 set(BRPC_CXX_STANDARD 14)
 
-set(WITH_GLOG_VAL "0")
-if(WITH_GLOG)
-    set(WITH_GLOG_VAL "1")
-    set(BRPC_WITH_GLOG 1)
-endif()
-
-set(WITH_CPU_FREQUENCY_VAL "0")
-if(WITH_CPU_FREQUENCY)
-    set(WITH_CPU_FREQUENCY_VAL "1")
-    set(BUTIL_USE_CPU_FREQUENCY 1)
-endif()
-
 if(WITH_DEBUG_SYMBOLS)
     list(APPEND BRPC_COMMON_COMPILE_OPTIONS -g)
 endif()
 
-set(WITH_DEBUG_LOCK_VAL "0")
-if(WITH_DEBUG_LOCK)
-    set(WITH_DEBUG_LOCK_VAL "1")
-endif()
-
-if(WITH_THRIFT)
-    list(APPEND BRPC_COMMON_DEFINITIONS ENABLE_THRIFT_FRAMED_PROTOCOL)
-    find_library(THRIFT_LIB NAMES thrift)
-    if (NOT THRIFT_LIB)
-        message(FATAL_ERROR "Fail to find Thrift")
-    endif()
-endif()
-
-if (WITH_BTHREAD_TRACER)
-    if (NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux")  OR NOT 
(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64"))
-        message(FATAL_ERROR "bthread tracer is only supported on Linux x86_64 
platform")
-    endif()
-    find_path(LIBUNWIND_INCLUDE_PATH NAMES libunwind.h)
-    find_library(LIBUNWIND_LIB NAMES unwind)
-    find_library(LIBUNWIND_X86_64_LIB NAMES unwind-x86_64)
-    if (NOT LIBUNWIND_INCLUDE_PATH OR NOT LIBUNWIND_LIB)
-        message(FATAL_ERROR "Fail to find libunwind, which is needed by 
bthread tracer")
-    endif()
-    find_package(absl REQUIRED CONFIG)
-    set(bthread_tracer_ABSL_USED_TARGETS absl::base absl::stacktrace 
absl::symbolize)
-    list(APPEND BRPC_COMMON_DEFINITIONS BRPC_BTHREAD_TRACER)
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${LIBUNWIND_INCLUDE_PATH})
-endif ()
-
-set(WITH_RDMA_VAL "0")
-if(WITH_RDMA)
-    set(WITH_RDMA_VAL "1")
-endif()
-
-set(WITH_URMA_VAL "0")
-if(WITH_URMA)
-    set(WITH_URMA_VAL "1")
-endif()
-
-string(TOUPPER "${URMA_USE_MOCK}" URMA_USE_MOCK_MODE)
-if(NOT URMA_USE_MOCK_MODE STREQUAL "AUTO" AND
-   NOT URMA_USE_MOCK_MODE STREQUAL "ON" AND
-   NOT URMA_USE_MOCK_MODE STREQUAL "OFF")
-    message(FATAL_ERROR
-        "URMA_USE_MOCK must be AUTO, ON, or OFF, got: ${URMA_USE_MOCK}")
-endif()
-
-set(WITH_UBRING_VAL "0")
-if(WITH_UBRING)
-        set(WITH_UBRING_VAL "1")
-endif()
-
-set(WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL "0")
-if(WITH_DEBUG_BTHREAD_SCHE_SAFETY)
-    set(WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL "1")
-endif()
-
 include(GNUInstallDirs)
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/bRPCHeaders.cmake)
 
-configure_file(${PROJECT_SOURCE_DIR}/config.h.in 
${PROJECT_SOURCE_DIR}/src/butil/config.h @ONLY)
-
-list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
 
 find_package(GFLAGS REQUIRED)
 
 execute_process(
-    COMMAND bash -c "${PROJECT_SOURCE_DIR}/tools/get_brpc_revision.sh 
${PROJECT_SOURCE_DIR} | tr -d '\n'"
+    COMMAND bash -c "${CMAKE_CURRENT_SOURCE_DIR}/tools/get_brpc_revision.sh 
${CMAKE_CURRENT_SOURCE_DIR} | tr -d '\n'"
     OUTPUT_VARIABLE BRPC_REVISION
 )
 string(REPLACE "\\|" "|" BRPC_REVISION "${BRPC_REVISION}")
 
 if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
-    include(CheckFunctionExists)
-    CHECK_FUNCTION_EXISTS(clock_gettime HAVE_CLOCK_GETTIME)
-    if(NOT HAVE_CLOCK_GETTIME)
-        list(APPEND BRPC_COMMON_DEFINITIONS NO_CLOCK_GETTIME_IN_MAC)
-    endif()
     list(APPEND BRPC_COMMON_COMPILE_OPTIONS
         -Wno-deprecated-declarations
         -Wno-inconsistent-missing-override
@@ -176,14 +101,6 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
 endif()
 
 list(APPEND BRPC_COMMON_DEFINITIONS
-    BRPC_WITH_GLOG=${WITH_GLOG_VAL}
-    BRPC_WITH_RDMA=${WITH_RDMA_VAL}
-    BRPC_WITH_URMA=${WITH_URMA_VAL}
-    BRPC_WITH_UBRING=${WITH_UBRING_VAL}
-    BRPC_DEBUG_BTHREAD_SCHE_SAFETY=${WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL}
-    BRPC_DEBUG_LOCK=${WITH_DEBUG_LOCK_VAL}
-    BUTIL_USE_CPU_FREQUENCY=${WITH_CPU_FREQUENCY_VAL}
-    BTHREAD_USE_FAST_PTHREAD_MUTEX
     __const__=__unused__
     _GNU_SOURCE
     USE_SYMBOLIZE
@@ -197,9 +114,6 @@ if(WITH_ASAN)
     list(APPEND BRPC_COMMON_COMPILE_OPTIONS -fsanitize=address)
     list(APPEND BRPC_COMMON_LINK_OPTIONS -fsanitize=address)
 endif()
-if(WITH_MESALINK)
-    list(APPEND BRPC_COMMON_DEFINITIONS USE_MESALINK)
-endif()
 
 list(APPEND BRPC_COMMON_COMPILE_OPTIONS
     -O2
@@ -215,19 +129,13 @@ list(APPEND BRPC_COMMON_COMPILE_OPTIONS
 )
 
 if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-    #required by butil/crc32.cc to boost performance for 10x
-    if((CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") AND NOT 
(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4))
-        list(APPEND BRPC_COMMON_COMPILE_OPTIONS
-            $<$<COMPILE_LANGUAGE:CXX>:-msse4>
-            $<$<COMPILE_LANGUAGE:CXX>:-msse4.2>
-        )
-    elseif((CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64"))
-        # segmentation fault in libcontext
+    if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+        # Preserve the libcontext workaround until its scope is verified.
         list(APPEND BRPC_COMMON_COMPILE_OPTIONS 
$<$<COMPILE_LANGUAGE:CXX>:-fno-gcse>)
-    elseif((CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64"))
-        # RISC-V specific optimizations
+    elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "riscv64")
         option(WITH_RISCV_ZBC "Enable RISC-V Zbc carry-less multiplication for 
CRC32C acceleration" OFF)
         option(WITH_RISCV_ZVBC "Enable RISC-V Zvbc vector carry-less 
multiplication for CRC32C acceleration" OFF)
+        # The ISA controls RVV code paths throughout the project, not just 
CRC32C.
         if(WITH_RISCV_ZVBC)
             list(APPEND BRPC_COMMON_COMPILE_OPTIONS 
$<$<COMPILE_LANGUAGE:CXX>:-march=rv64gcv_zbc_zvbc>)
         elseif(WITH_RISCV_ZBC)
@@ -242,7 +150,9 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
 endif()
 
 find_package(Protobuf REQUIRED)
-find_package(ZLIB REQUIRED)
+foreach(protobuf_include_dir IN LISTS Protobuf_INCLUDE_DIRS)
+    list(APPEND PROTOC_FLAGS -I${protobuf_include_dir})
+endforeach()
 if(Protobuf_VERSION VERSION_GREATER 4.21)
     # required by absl
     set(BRPC_CXX_STANDARD 17)
@@ -289,229 +199,9 @@ if(Protobuf_VERSION VERSION_GREATER 4.21)
 endif()
 find_package(Threads REQUIRED)
 
-find_path(LEVELDB_INCLUDE_PATH NAMES leveldb/db.h)
-find_library(LEVELDB_LIB NAMES leveldb)
-if ((NOT LEVELDB_INCLUDE_PATH) OR (NOT LEVELDB_LIB))
-    message(FATAL_ERROR "Fail to find leveldb")
-endif()
-
-if(WITH_SNAPPY)
-    find_path(SNAPPY_INCLUDE_PATH NAMES snappy.h)
-    find_library(SNAPPY_LIB NAMES snappy)
-    if ((NOT SNAPPY_INCLUDE_PATH) OR (NOT SNAPPY_LIB))
-        message(FATAL_ERROR "Fail to find snappy")
-    endif()
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${SNAPPY_INCLUDE_PATH})
-endif()
-
-if(WITH_GLOG)
-    find_path(GLOG_INCLUDE_PATH NAMES glog/logging.h)
-    find_library(GLOG_LIB NAMES glog)
-    if((NOT GLOG_INCLUDE_PATH) OR (NOT GLOG_LIB))
-        message(FATAL_ERROR "Fail to find glog")
-    endif()
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${GLOG_INCLUDE_PATH})
-endif()
-
-if(WITH_MESALINK)
-    find_path(MESALINK_INCLUDE_PATH NAMES mesalink/openssl/ssl.h)
-    find_library(MESALINK_LIB NAMES mesalink)
-    if((NOT MESALINK_INCLUDE_PATH) OR (NOT MESALINK_LIB))
-        message(FATAL_ERROR "Fail to find MesaLink")
-    else()
-        message(STATUS "Found MesaLink: ${MESALINK_LIB}")
-    endif()
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${MESALINK_INCLUDE_PATH})
-endif()
-
-if(WITH_RDMA)
-    message("brpc compile with rdma")
-    find_path(RDMA_INCLUDE_PATH NAMES infiniband/verbs.h)
-    find_library(RDMA_LIB NAMES ibverbs)
-    if((NOT RDMA_INCLUDE_PATH) OR (NOT RDMA_LIB))
-        message(FATAL_ERROR "Fail to find ibverbs")
-    endif()
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${RDMA_INCLUDE_PATH})
-endif()
-
-if(WITH_URMA)
-    # UrmaTransport and its link-time mock both compile against the upstream
-    # UMDK API. Prefer installed headers; otherwise fetch a pinned upstream
-    # commit, following Mooncake's URMA mock setup.
-    find_path(URMA_INCLUDE_PATH NAMES urma_api.h
-              HINTS ENV URMA_ROOT
-              PATHS /usr/include /usr/local/include
-              PATH_SUFFIXES ub/umdk/urma umdk/urma urma
-                            src/urma/lib/urma/core/include)
-    find_path(URMA_BOND_INCLUDE_PATH NAMES urma_ubagg.h
-              HINTS ENV URMA_ROOT
-              PATHS /usr/include /usr/local/include
-              PATH_SUFFIXES ub/umdk/urma umdk/urma urma
-                            src/urma/lib/urma/bond/include)
-    if(NOT URMA_INCLUDE_PATH AND DOWNLOAD_URMA_HEADERS)
-        include(FetchContent)
-        FetchContent_Declare(
-            urma_headers
-            GIT_REPOSITORY https://atomgit.com/openeuler/umdk.git
-            GIT_TAG 564ee727a55523d4351a8fb3c94292b388ebb924
-            # brpc only consumes UMDK headers; avoid cloning unrelated UMDK
-            # submodules such as CAM dependencies during configuration.
-            GIT_SUBMODULES ""
-            GIT_SHALLOW TRUE)
-        FetchContent_GetProperties(urma_headers)
-        if(NOT urma_headers_POPULATED)
-            FetchContent_Populate(urma_headers)
-        endif()
-        set(URMA_INCLUDE_PATH
-            "${urma_headers_SOURCE_DIR}/src/urma/lib/urma/core/include")
-        set(URMA_BOND_INCLUDE_PATH
-            "${urma_headers_SOURCE_DIR}/src/urma/lib/urma/bond/include")
-        message(STATUS "Using downloaded UMDK headers: ${URMA_INCLUDE_PATH}")
-    endif()
-    if(NOT URMA_INCLUDE_PATH)
-        message(FATAL_ERROR
-            "Fail to find urma_api.h. Install UMDK headers, set URMA_ROOT, "
-            "or enable DOWNLOAD_URMA_HEADERS.")
-    endif()
-
-    find_library(URMA_LIB NAMES urma
-                 HINTS ENV URMA_ROOT
-                 PATH_SUFFIXES lib lib64)
-    if(URMA_USE_MOCK_MODE STREQUAL "ON")
-        message(STATUS "URMA_USE_MOCK=ON; forcing the link-time URMA mock")
-        set(URMA_USE_MOCK_ENABLED 1)
-    elseif(URMA_USE_MOCK_MODE STREQUAL "OFF")
-        if(NOT URMA_LIB)
-            message(FATAL_ERROR
-                "URMA_USE_MOCK=OFF requires liburma; install it or use 
AUTO/ON.")
-        endif()
-        message(STATUS "URMA_USE_MOCK=OFF; using liburma")
-        set(URMA_USE_MOCK_ENABLED 0)
-    elseif(URMA_LIB)
-        message(STATUS "Found URMA library: ${URMA_LIB}")
-        set(URMA_USE_MOCK_ENABLED 0)
-    else()
-        message(STATUS
-            "liburma not found; building with the URMA link-time mock")
-        set(URMA_USE_MOCK_ENABLED 1)
-    endif()
-endif()
-
-find_library(PROTOC_LIB NAMES protoc)
-if(NOT PROTOC_LIB)
-    message(FATAL_ERROR "Fail to find protoc lib")
-endif()
-
-if(WITH_BORINGSSL)
-    find_package(BoringSSL REQUIRED)
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${BORINGSSL_INCLUDE_DIR})
-else()
-    if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT OPENSSL_ROOT_DIR)
-        set(OPENSSL_ROOT_DIR
-            "/usr/local/opt/openssl" # Homebrew installed OpenSSL
-        )
-    endif()
-
-    find_package(OpenSSL REQUIRED)
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
-endif()
-
-list(APPEND BRPC_COMMON_INCLUDE_DIRS
-    ${GFLAGS_INCLUDE_PATH}
-    ${PROTOBUF_INCLUDE_DIRS}
-    ${LEVELDB_INCLUDE_PATH}
-)
-if(WITH_URMA)
-    list(APPEND BRPC_COMMON_INCLUDE_DIRS ${URMA_INCLUDE_PATH})
-    if(URMA_BOND_INCLUDE_PATH)
-        list(APPEND BRPC_COMMON_INCLUDE_DIRS ${URMA_BOND_INCLUDE_PATH})
-    endif()
-endif()
-
-set(DYNAMIC_LIB
-    ${GFLAGS_LIBRARY}
-    ${PROTOBUF_LIBRARIES} ${protobuf_ABSL_USED_TARGETS}
-    ${LEVELDB_LIB}
-    ${PROTOC_LIB}
-    ${CMAKE_THREAD_LIBS_INIT}
-    ${THRIFT_LIB}
-    dl
-    ZLIB::ZLIB)
-
-if(WITH_BORINGSSL)
-    list(APPEND DYNAMIC_LIB ${BORINGSSL_SSL_LIBRARY})
-    list(APPEND DYNAMIC_LIB ${BORINGSSL_CRYPTO_LIBRARY})
-else()
-    if(WITH_MESALINK)
-        list(APPEND DYNAMIC_LIB ${OPENSSL_CRYPTO_LIBRARY})
-        list(APPEND DYNAMIC_LIB ${MESALINK_LIB})
-    else()
-        list(APPEND DYNAMIC_LIB ${OPENSSL_SSL_LIBRARY})
-        list(APPEND DYNAMIC_LIB ${OPENSSL_CRYPTO_LIBRARY})
-    endif()
-endif()
-
-if(WITH_RDMA)
-    list(APPEND DYNAMIC_LIB ${RDMA_LIB})
-endif()
-
-if(WITH_URMA)
-    message(STATUS "brpc compile with URMA (mock=${URMA_USE_MOCK_ENABLED})")
-    if(NOT URMA_USE_MOCK_ENABLED)
-        list(APPEND DYNAMIC_LIB ${URMA_LIB})
-    endif()
-endif()
-
-if(WITH_UBRING)
-    message(STATUS "brpc compile with ubring")
-    list(APPEND DYNAMIC_LIB ${UB_LIB})
-endif()
-
-set(BRPC_PRIVATE_LIBS "-lgflags -lprotobuf -lleveldb -lprotoc -lssl -lcrypto 
-ldl -lz")
-
-if(WITH_GLOG)
-    set(DYNAMIC_LIB ${GLOG_LIB} ${DYNAMIC_LIB})
-    set(BRPC_PRIVATE_LIBS "-lglog ${BRPC_PRIVATE_LIBS}")
-endif()
-
-if(WITH_SNAPPY)
-    set(DYNAMIC_LIB ${DYNAMIC_LIB} ${SNAPPY_LIB})
-    set(BRPC_PRIVATE_LIBS "${BRPC_PRIVATE_LIBS} -lsnappy")
-endif()
-
-if (WITH_BTHREAD_TRACER)
-    set(DYNAMIC_LIB ${DYNAMIC_LIB} ${LIBUNWIND_LIB} ${LIBUNWIND_X86_64_LIB} 
${bthread_tracer_ABSL_USED_TARGETS})
-    set(BRPC_PRIVATE_LIBS "${BRPC_PRIVATE_LIBS} -lunwind -lunwind-x86_64  
-labsl_stacktrace -labsl_symbolize -labsl_debugging_internal 
-labsl_demangle_internal -labsl_malloc_internal -labsl_raw_logging_internal 
-labsl_spinlock_wait -labsl_base")
-endif()
-
-if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-    set(DYNAMIC_LIB ${DYNAMIC_LIB} rt)
-    set(BRPC_PRIVATE_LIBS "${BRPC_PRIVATE_LIBS} -lrt")
-elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
-    set(DYNAMIC_LIB ${DYNAMIC_LIB}
-        pthread
-        "-framework CoreFoundation"
-        "-framework CoreGraphics"
-        "-framework CoreData"
-        "-framework CoreText"
-        "-framework Security"
-        "-framework Foundation"
-        "-Wl,-U,_MallocExtension_ReleaseFreeMemory"
-        "-Wl,-U,_ProfilerStart"
-        "-Wl,-U,_ProfilerStop"
-        "-Wl,-U,__Z13GetStackTracePPvii"
-        "-Wl,-U,_mallctl"
-        "-Wl,-U,_malloc_stats_print"
-    )
-endif()
-
 list(REMOVE_DUPLICATES BRPC_COMMON_INCLUDE_DIRS)
 
 add_library(brpc_common_config INTERFACE)
-# Generated protobuf headers live in the build directory. Search it before src/
-# so leftover in-source *.pb.h (gitignored, produced by Make) cannot shadow
-# updated .proto files such as errno.proto.
-target_include_directories(brpc_common_config BEFORE INTERFACE 
${CMAKE_CURRENT_BINARY_DIR})
 target_include_directories(brpc_common_config INTERFACE 
${BRPC_COMMON_INCLUDE_DIRS})
 target_compile_definitions(brpc_common_config INTERFACE 
${BRPC_COMMON_DEFINITIONS})
 target_compile_options(brpc_common_config INTERFACE 
${BRPC_COMMON_COMPILE_OPTIONS})
@@ -525,258 +215,21 @@ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY 
${PROJECT_BINARY_DIR}/output/lib)
 # for *.a
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/output/lib)
 
-# the reason why not using file(GLOB_RECURSE...) is that we want to
-# include different files on different platforms.
-set(BUTIL_SOURCES
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/dmg_fp/g_fmt.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/dmg_fp/dtoa_wrapper.cc
-    
${PROJECT_SOURCE_DIR}/src/butil/third_party/dynamic_annotations/dynamic_annotations.c
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/icu/icu_utf.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/superfasthash/superfasthash.c
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/modp_b64/modp_b64.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/modp_b64/modp_b64_rvv.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/symbolize/demangle.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/symbolize/symbolize.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/snappy/snappy-sinksource.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/snappy/snappy-stubs-internal.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/snappy/snappy.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/third_party/murmurhash3/murmurhash3.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/arena.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/at_exit.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/atomicops_internals_x86_gcc.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/base64.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/base64url.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/big_endian.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/cpu.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/alias.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/asan_invalid_access.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/crash_logging.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/debugger.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/debugger_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/dump_without_crashing.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/proc_maps_linux.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/stack_trace.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/debug/stack_trace_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/environment.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file_enumerator.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file_enumerator_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file_path.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file_path_constants.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/memory_mapped_file.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/memory_mapped_file_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/scoped_file.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/files/scoped_temp_dir.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/file_util.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/file_util_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/guid.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/guid_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/hash.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/lazy_instance.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/location.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/memory/aligned_memory.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/memory/ref_counted.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/memory/ref_counted_memory.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/memory/singleton.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/memory/weak_ptr.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/posix/file_descriptor_shuffle.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/posix/global_descriptors.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/process_util.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/rand_util.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/rand_util_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/fast_rand.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/safe_strerror_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/sha1_portable.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/latin1_string_conversions.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/nullable_string16.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/safe_sprintf.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/string16.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/string_number_conversions.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/string_split.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/string_piece.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/string_compare_rvv.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/string_util.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/string_util_constants.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/stringprintf.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/utf_offset_string_conversions.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/utf_string_conversion_utils.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/strings/utf_string_conversions.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/synchronization/cancellation_flag.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/synchronization/condition_variable_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/synchronization/waitable_event_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/non_thread_safe_impl.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/platform_thread_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/simple_thread.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_checker_impl.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_collision_warner.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_id_name_manager.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_local_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_local_storage.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_local_storage_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/thread_restrictions.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/threading/watchdog.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/time/clock.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/time/default_clock.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/time/default_tick_clock.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/time/tick_clock.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/time/time.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/time/time_posix.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/version.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/logging.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/class_name.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/errno.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/find_cstr.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/status.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/string_printf.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/thread_local.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/thread_key.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/unix_socket.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/endpoint.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/fd_utility.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/files/temp_file.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/files/file_watcher.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/time.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/zero_copy_stream_as_streambuf.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/crc32c.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/containers/case_ignored_flat_map.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/iobuf.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/single_iobuf.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/iobuf_profiler.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/binary_printer.cpp
-    ${PROJECT_SOURCE_DIR}/src/butil/recordio.cc
-    ${PROJECT_SOURCE_DIR}/src/butil/popen.cpp
-    )
-
-if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
-    set(BUTIL_SOURCES ${BUTIL_SOURCES}
-        ${PROJECT_SOURCE_DIR}/src/butil/file_util_linux.cc
-        ${PROJECT_SOURCE_DIR}/src/butil/threading/platform_thread_linux.cc
-        
${PROJECT_SOURCE_DIR}/src/butil/strings/sys_string_conversions_posix.cc)
-elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
-    set(BUTIL_SOURCES ${BUTIL_SOURCES}
-        ${PROJECT_SOURCE_DIR}/src/butil/mac/bundle_locations.mm
-        ${PROJECT_SOURCE_DIR}/src/butil/mac/foundation_util.mm
-        ${PROJECT_SOURCE_DIR}/src/butil/file_util_mac.mm
-        ${PROJECT_SOURCE_DIR}/src/butil/threading/platform_thread_mac.mm
-        ${PROJECT_SOURCE_DIR}/src/butil/strings/sys_string_conversions_mac.mm
-        ${PROJECT_SOURCE_DIR}/src/butil/time/time_mac.cc
-        ${PROJECT_SOURCE_DIR}/src/butil/mac/scoped_mach_port.cc)
-endif()
-
-file(GLOB_RECURSE BVAR_SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/src/bvar/*.cpp")
-file(GLOB_RECURSE BTHREAD_SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/src/bthread/*.cpp")
-file(GLOB_RECURSE JSON2PB_SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/src/json2pb/*.cpp")
-file(GLOB_RECURSE BRPC_SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/src/brpc/*.cpp")
-file(GLOB_RECURSE THRIFT_SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/src/brpc/thrift*.cpp")
-file(GLOB_RECURSE EXCLUDE_SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/src/brpc/event_dispatcher_*.cpp")
-
-# When building with the real liburma, exclude the link-time mock so its urma_*
-# symbols do not clash with the library. When liburma is absent, keep it so CI
-# can build and test UrmaTransport without URMA hardware.
-if(WITH_URMA AND NOT URMA_USE_MOCK_ENABLED)
-    list(REMOVE_ITEM BRPC_SOURCES
-         "${PROJECT_SOURCE_DIR}/src/brpc/urma/mock_urma.cpp")
-endif()
-
-if(WITH_THRIFT)
-    message("brpc compile with thrift protocol")
-else()
-    # Remove thrift sources
-    foreach(v ${THRIFT_SOURCES})
-        list(REMOVE_ITEM BRPC_SOURCES ${v})
-    endforeach()
-    set(THRIFT_SOURCES "")
-endif()
-
-foreach(v ${EXCLUDE_SOURCES})
-    list(REMOVE_ITEM BRPC_SOURCES ${v})
-endforeach()
-
-set(MCPACK2PB_SOURCES
-    ${PROJECT_SOURCE_DIR}/src/mcpack2pb/field_type.cpp
-    ${PROJECT_SOURCE_DIR}/src/mcpack2pb/mcpack2pb.cpp
-    ${PROJECT_SOURCE_DIR}/src/mcpack2pb/parser.cpp
-    ${PROJECT_SOURCE_DIR}/src/mcpack2pb/serializer.cpp)
-
-include(CompileProto)
-set(PROTO_FILES idl_options.proto
-                brpc/rtmp.proto
-                brpc/rpc_dump.proto
-                brpc/get_favicon.proto
-                brpc/span.proto
-                brpc/builtin_service.proto
-                brpc/grpc_health_check.proto
-                brpc/get_js.proto
-                brpc/errno.proto
-                brpc/nshead_meta.proto
-                brpc/options.proto
-                brpc/policy/baidu_rpc_meta.proto
-                brpc/policy/hulu_pbrpc_meta.proto
-                brpc/policy/public_pbrpc_meta.proto
-                brpc/policy/sofa_pbrpc_meta.proto
-                brpc/policy/mongo.proto
-                brpc/trackme.proto
-                brpc/streaming_rpc_meta.proto
-                brpc/proto_base.proto
-                brpc/rdma/rdma_handshake.proto
-                brpc/urma/urma_handshake.proto)
-file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/output/include/brpc)
-set(PROTOC_FLAGS ${PROTOC_FLAGS} -I${PROTOBUF_INCLUDE_DIR})
-compile_proto(PROTO_HDRS PROTO_SRCS ${PROJECT_BINARY_DIR}
-                                    ${PROJECT_BINARY_DIR}/output/include
-                                    ${PROJECT_SOURCE_DIR}/src
-                                    "${PROTO_FILES}")
-add_library(PROTO_LIB OBJECT ${PROTO_SRCS} ${PROTO_HDRS})
-target_link_libraries(PROTO_LIB PRIVATE brpc_common_config)
-
-set(SOURCES
-    ${BVAR_SOURCES}
-    ${BTHREAD_SOURCES}
-    ${JSON2PB_SOURCES}
-    ${MCPACK2PB_SOURCES}
-    ${BRPC_SOURCES}
-    ${THRIFT_SOURCES}
-    )
-
 add_subdirectory(src)
+add_subdirectory(test/cmake_link_dependencies EXCLUDE_FROM_ALL)
 if(BUILD_UNIT_TESTS)
     enable_testing()
     add_subdirectory(test)
 endif()
 
-if(BUILD_FUZZ_TESTS)
-    if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
-        message(FATAL_ERROR "Fuzzing is only supported with clang")
-    endif()
-    if(NOT BUILD_UNIT_TESTS)
-        message(FATAL_ERROR "BUILD_UNIT_TESTS must be enabled to build fuzz 
tests")
-    endif()
+if(BUILD_FUZZ_TESTS AND NOT BUILD_UNIT_TESTS)
+    message(FATAL_ERROR "BUILD_UNIT_TESTS must be enabled to build fuzz tests")
 endif()
 
 if(BUILD_BRPC_TOOLS)
     add_subdirectory(tools)
 endif()
 
-file(COPY ${CMAKE_CURRENT_BINARY_DIR}/brpc/
-        DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/output/include/brpc/
-        FILES_MATCHING
-        PATTERN "*.h"
-        PATTERN "*.hpp"
-        )
-file(COPY ${PROJECT_SOURCE_DIR}/src/
-        DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/output/include/
-        FILES_MATCHING
-        PATTERN "*.h"
-        PATTERN "*.hpp"
-        )
-install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/output/include/
-        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
-        FILES_MATCHING
-        PATTERN "*.h"
-        PATTERN "*.hpp"
-        )
-
 # Install pkgconfig
 configure_file(cmake/brpc.pc.in ${PROJECT_BINARY_DIR}/brpc.pc @ONLY)
 install(FILES ${PROJECT_BINARY_DIR}/brpc.pc DESTINATION 
${CMAKE_INSTALL_LIBDIR}/pkgconfig)
diff --git a/cmake/CompileProto.cmake b/cmake/CompileProto.cmake
index d4e24408..73c11ebd 100644
--- a/cmake/CompileProto.cmake
+++ b/cmake/CompileProto.cmake
@@ -13,10 +13,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-function(compile_proto OUT_HDRS OUT_SRCS DESTDIR HDR_OUTPUT_DIR PROTO_DIR 
PROTO_FILES)
+function(compile_proto OUT_HDRS OUT_SRCS DESTDIR PROTO_DIR PROTO_FILES)
   foreach(P ${PROTO_FILES})
     string(REPLACE .proto .pb.h HDR ${P})
-    set(HDR_RELATIVE ${HDR})
     set(HDR ${DESTDIR}/${HDR})
     string(REPLACE .proto .pb.cc SRC ${P})
     set(SRC ${DESTDIR}/${SRC})
@@ -25,7 +24,6 @@ function(compile_proto OUT_HDRS OUT_SRCS DESTDIR 
HDR_OUTPUT_DIR PROTO_DIR PROTO_
     add_custom_command(
       OUTPUT ${HDR} ${SRC}
       COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} ${PROTOC_FLAGS} -I${PROTO_DIR} 
--cpp_out=${DESTDIR} ${PROTO_DIR}/${P}
-      COMMAND ${CMAKE_COMMAND} -E copy ${HDR} ${HDR_OUTPUT_DIR}/${HDR_RELATIVE}
       DEPENDS ${PROTO_DIR}/${P}
     )
   endforeach()
diff --git a/cmake/SetupGtest.cmake b/cmake/SetupGtest.cmake
index 33e701c7..e055e5e2 100644
--- a/cmake/SetupGtest.cmake
+++ b/cmake/SetupGtest.cmake
@@ -14,7 +14,7 @@
 # limitations under the License.
 
 # Setup googletest
-configure_file("${PROJECT_SOURCE_DIR}/cmake/CMakeLists.download_gtest.in" 
${PROJECT_BINARY_DIR}/googletest-download/CMakeLists.txt)
+configure_file("${CMAKE_CURRENT_LIST_DIR}/CMakeLists.download_gtest.in" 
${PROJECT_BINARY_DIR}/googletest-download/CMakeLists.txt)
 
 execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
                 RESULT_VARIABLE result
diff --git a/cmake/bRPCHeaders.cmake b/cmake/bRPCHeaders.cmake
new file mode 100644
index 00000000..e45dd97c
--- /dev/null
+++ b/cmake/bRPCHeaders.cmake
@@ -0,0 +1,37 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+# Install headers from their owners, without a build-tree staging directory.
+function(brpc_install_module_headers)
+    get_filename_component(include_root "${CMAKE_CURRENT_SOURCE_DIR}/.." 
ABSOLUTE)
+    file(GLOB_RECURSE headers CONFIGURE_DEPENDS
+        "${CMAKE_CURRENT_SOURCE_DIR}/*.h"
+        "${CMAKE_CURRENT_SOURCE_DIR}/*.hpp")
+    list(FILTER headers EXCLUDE REGEX "\\.pb\\.h$")
+    # Make/Bazel may leave a configuration header that belongs to another 
build.
+    list(REMOVE_ITEM headers "${include_root}/butil/config.h")
+    brpc_install_headers(${include_root} ${headers})
+endfunction()
+
+function(brpc_install_headers include_root)
+    foreach(header IN LISTS ARGN)
+        file(RELATIVE_PATH relative_header ${include_root} ${header})
+        get_filename_component(include_subdir ${relative_header} DIRECTORY)
+        install(FILES ${header}
+            DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${include_subdir})
+    endforeach()
+endfunction()
diff --git a/docs/cn/getting_started.md b/docs/cn/getting_started.md
index b8fdb536..2a3f98d1 100644
--- a/docs/cn/getting_started.md
+++ b/docs/cn/getting_started.md
@@ -105,9 +105,17 @@ cmake -B build && cmake --build build -j6
 
 **用cmake运行样例**
 
+先在仓库根目录安装 brpc。CMake 会直接安装头文件和库,不再在编译时将
+头文件暂存到 `output/include`。在配置阶段设置安装前缀,确保生成的
+pkg-config 元数据使用相同的前缀,再将此前缀传给样例:
+
 ```shell
+$ cmake -S . -B build -DCMAKE_INSTALL_PREFIX="$PWD/build/output"
+$ cmake --build build -j6
+$ cmake --install build
 $ cd example/echo_c++
-$ cmake -B build && cmake --build build -j4
+$ cmake -B build -DCMAKE_PREFIX_PATH="$PWD/../../build/output"
+$ cmake --build build -j4
 $ cd build
 $ ./echo_server &
 $ ./echo_client
diff --git a/docs/cn/ubring.md b/docs/cn/ubring.md
index 1db99091..338b49a6 100644
--- a/docs/cn/ubring.md
+++ b/docs/cn/ubring.md
@@ -55,12 +55,14 @@ UBRing 支持两种共享内存后端,通过 `ub_shm_type` 参数控制:
 ```bash
 # 构建 brpc 并启用 UBRing 支持
 cd /path/to/brpc
-cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DWITH_UBRING:BOOL=ON
+cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DWITH_UBRING:BOOL=ON \
+  -DCMAKE_INSTALL_PREFIX="$PWD/build/output"
 cmake --build build -j 8
+cmake --install build
 
 # 构建 ubring_performance 示例
 cd /path/to/brpc/example/ubring_performance
-cmake -B build
+cmake -B build -DCMAKE_PREFIX_PATH="$PWD/../../build/output"
 cmake --build build -j 8
 ```
 
@@ -100,10 +102,12 @@ brpc 在 `example/ubring_performance/` 目录提供了性能测试示例。
 
 #### 构建示例
 
+先按[使用 CMake 构建](#使用-cmake-构建)中的步骤编译并安装 brpc。
+
 ```bash
-cd example/ubring_performance
+cd /path/to/brpc/example/ubring_performance
 mkdir -p build && cd build
-cmake ..
+cmake .. -DCMAKE_PREFIX_PATH="$PWD/../../../build/output"
 make
 ```
 
diff --git a/docs/en/getting_started.md b/docs/en/getting_started.md
index d605975e..cabd5ecc 100644
--- a/docs/en/getting_started.md
+++ b/docs/en/getting_started.md
@@ -94,9 +94,19 @@ To enable [thrift support](../en/thrift.md), install thrift 
first and cmake with
 
 **Run example with cmake**
 
+Install brpc from the repository root first. CMake installs headers and
+libraries directly; it no longer stages headers in `output/include` during
+the build. Set the installation prefix during configuration so that generated
+pkg-config metadata uses the same prefix, then pass it to the example:
+
 ```shell
+$ cmake -S . -B build -DCMAKE_INSTALL_PREFIX="$PWD/build/output"
+$ cmake --build build -j6
+$ cmake --install build
 $ cd example/echo_c++
-$ cmake -B build && cmake --build build -j4
+$ cmake -B build -DCMAKE_PREFIX_PATH="$PWD/../../build/output"
+$ cmake --build build -j4
+$ cd build
 $ ./echo_server &
 $ ./echo_client
 ```
diff --git a/docs/en/ubring.md b/docs/en/ubring.md
index fbf87fff..4779f9c2 100644
--- a/docs/en/ubring.md
+++ b/docs/en/ubring.md
@@ -54,12 +54,14 @@ To build brpc with UBRing support, use the following 
commands:
 ```bash
 # Build brpc with UBRing support
 cd /path/to/brpc
-cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DWITH_UBRING:BOOL=ON
+cmake -B build -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DWITH_UBRING:BOOL=ON \
+  -DCMAKE_INSTALL_PREFIX="$PWD/build/output"
 cmake --build build -j 8
+cmake --install build
 
 # Build the ubring_performance example
 cd /path/to/brpc/example/ubring_performance
-cmake -B build
+cmake -B build -DCMAKE_PREFIX_PATH="$PWD/../../build/output"
 cmake --build build -j 8
 ```
 
@@ -99,10 +101,12 @@ brpc provides a performance test example at 
`example/ubring_performance/`.
 
 #### Build the Example
 
+First build and install brpc as described in [Build with 
CMake](#build-with-cmake).
+
 ```bash
-cd example/ubring_performance
+cd /path/to/brpc/example/ubring_performance
 mkdir -p build && cd build
-cmake ..
+cmake .. -DCMAKE_PREFIX_PATH="$PWD/../../../build/output"
 make
 ```
 
diff --git a/example/cmake/BrpcExample.cmake b/example/cmake/BrpcExample.cmake
index 6b2c7850..60e3591f 100644
--- a/example/cmake/BrpcExample.cmake
+++ b/example/cmake/BrpcExample.cmake
@@ -28,15 +28,7 @@ function(brpc_example_append_existing_dirs out_var)
 endfunction()
 
 macro(brpc_example_find_common_deps out_libs)
-    execute_process(
-        COMMAND bash -c "find ${PROJECT_SOURCE_DIR}/../.. -type d -regex 
\".*output/include$\" | head -n1 | xargs dirname | tr -d '\n'"
-        OUTPUT_VARIABLE OUTPUT_PATH
-    )
-
-    if(OUTPUT_PATH)
-        list(PREPEND CMAKE_PREFIX_PATH ${OUTPUT_PATH})
-    endif()
-
+    # Locate an installed bundle through the caller's CMAKE_PREFIX_PATH.
     find_package(Threads REQUIRED)
     find_package(Protobuf REQUIRED)
     set(BRPC_EXAMPLE_CXX_STANDARD 14)
@@ -126,7 +118,7 @@ macro(brpc_example_find_common_deps out_libs)
     set(_common_libs
         Threads::Threads
         ${GFLAGS_LIBRARY}
-        ${PROTOBUF_LIBRARIES}
+        protobuf::libprotobuf
         ${_protobuf_absl_targets}
         ${LEVELDB_LIB}
         ${OPENSSL_CRYPTO_LIBRARY}
diff --git a/example/dynamic_partition_echo_c++/CMakeLists.txt 
b/example/dynamic_partition_echo_c++/CMakeLists.txt
index 1fbc6d9f..0a198c2e 100644
--- a/example/dynamic_partition_echo_c++/CMakeLists.txt
+++ b/example/dynamic_partition_echo_c++/CMakeLists.txt
@@ -37,5 +37,5 @@ brpc_example_configure_target(dynamic_partition_echo_server)
 target_link_libraries(dynamic_partition_echo_client PRIVATE ${BRPC_LIB} 
${DYNAMIC_LIB} ${GPERFTOOLS_LIBRARIES})
 target_link_libraries(dynamic_partition_echo_server PRIVATE ${BRPC_LIB} 
${DYNAMIC_LIB} ${GPERFTOOLS_LIBRARIES})
 
-file(COPY ${PROJECT_SOURCE_DIR}/server_list
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/server_list
      DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/example/http_c++/CMakeLists.txt b/example/http_c++/CMakeLists.txt
index c29bbb7e..b58bf866 100644
--- a/example/http_c++/CMakeLists.txt
+++ b/example/http_c++/CMakeLists.txt
@@ -40,7 +40,7 @@ target_link_libraries(http_server PRIVATE ${BRPC_LIB} 
${DYNAMIC_LIB} ${GPERFTOOL
 target_link_libraries(http_client PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB} 
${GPERFTOOLS_LIBRARIES})
 target_link_libraries(benchmark_http PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB} 
${GPERFTOOLS_LIBRARIES})
 
-file(COPY ${PROJECT_SOURCE_DIR}/key.pem
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/key.pem
      DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/cert.pem
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/cert.pem
      DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/example/multi_threaded_echo_c++/CMakeLists.txt 
b/example/multi_threaded_echo_c++/CMakeLists.txt
index 7eaf4dfd..6b27b0fa 100644
--- a/example/multi_threaded_echo_c++/CMakeLists.txt
+++ b/example/multi_threaded_echo_c++/CMakeLists.txt
@@ -37,7 +37,7 @@ brpc_example_configure_target(echo_server)
 target_link_libraries(echo_client PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB} 
${GPERFTOOLS_LIBRARIES})
 target_link_libraries(echo_server PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB} 
${GPERFTOOLS_LIBRARIES})
 
-file(COPY ${PROJECT_SOURCE_DIR}/key.pem
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/key.pem
      DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/cert.pem
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/cert.pem
      DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/example/partition_echo_c++/CMakeLists.txt 
b/example/partition_echo_c++/CMakeLists.txt
index 8fcc620c..3ad3eb28 100644
--- a/example/partition_echo_c++/CMakeLists.txt
+++ b/example/partition_echo_c++/CMakeLists.txt
@@ -37,5 +37,5 @@ brpc_example_configure_target(server)
 target_link_libraries(client PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB} 
${GPERFTOOLS_LIBRARIES})
 target_link_libraries(server PRIVATE ${BRPC_LIB} ${DYNAMIC_LIB} 
${GPERFTOOLS_LIBRARIES})
 
-file(COPY ${PROJECT_SOURCE_DIR}/server_list
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/server_list
      DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
diff --git a/example/ubring_performance/CMakeLists.txt 
b/example/ubring_performance/CMakeLists.txt
index 43621862..7d9d7a5d 100644
--- a/example/ubring_performance/CMakeLists.txt
+++ b/example/ubring_performance/CMakeLists.txt
@@ -15,17 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 
-cmake_minimum_required(VERSION 2.8.10)
+cmake_minimum_required(VERSION 3.16...3.28)
 project(ubring_performance C CXX)
 
 option(LINK_SO "Whether examples are linked dynamically" OFF)
 
-execute_process(
-    COMMAND bash -c "find ${PROJECT_SOURCE_DIR}/../.. -type d -regex 
'.*output/include$' | head -n1 | xargs dirname | tr -d '\n'"
-    OUTPUT_VARIABLE OUTPUT_PATH
-)
-
-set(CMAKE_PREFIX_PATH ${OUTPUT_PATH})
+# Locate an installed bundle through the caller's CMAKE_PREFIX_PATH.
 
 include(FindThreads)
 include(FindProtobuf)
@@ -100,7 +95,7 @@ include_directories(${OPENSSL_INCLUDE_DIR})
 set(DYNAMIC_LIB
     ${CMAKE_THREAD_LIBS_INIT}
     ${GFLAGS_LIBRARY}
-    ${PROTOBUF_LIBRARIES}
+    protobuf::libprotobuf
     ${LEVELDB_LIB}
     ${OPENSSL_CRYPTO_LIBRARY}
     ${OPENSSL_SSL_LIBRARY}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 17fe2154..74dba91d 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,86 +15,74 @@
 # specific language governing permissions and limitations
 # under the License.
 
-add_library(BUTIL_LIB OBJECT ${BUTIL_SOURCES})
-add_library(SOURCES_LIB OBJECT ${SOURCES})
-add_dependencies(SOURCES_LIB PROTO_LIB)
-target_link_libraries(BUTIL_LIB PRIVATE brpc_common_config)
-target_link_libraries(SOURCES_LIB PRIVATE brpc_common_config)
+add_library(brpc_bundle_dependencies INTERFACE)
+
+add_subdirectory(butil)
+add_subdirectory(bvar)
+add_subdirectory(bthread)
+add_subdirectory(json2pb)
+add_subdirectory(mcpack2pb)
+add_subdirectory(brpc)
+
+# Modules report their bundle dependencies after applying their own options.
+set(DYNAMIC_LIB)
+set(bundle_system_libraries)
+set(component_private_libs)
+set(component_system_libs)
+# Consumers precede providers: libprotoc needs libprotobuf, and glog may need
+# gflags and the unwinder. System libraries follow all module dependencies.
+foreach(component MCPACK2PB BRPC BVAR JSON2PB BUTIL BTHREAD)
+    get_target_property(component_libraries ${component}_LIB 
BRPC_BUNDLE_LIBRARIES)
+    if(component_libraries)
+        list(APPEND DYNAMIC_LIB ${component_libraries})
+    endif()
+    get_target_property(component_pkgconfig ${component}_LIB BRPC_PRIVATE_LIBS)
+    if(component_pkgconfig)
+        list(APPEND component_private_libs "${component_pkgconfig}")
+    endif()
+    get_target_property(component_libraries ${component}_LIB 
BRPC_BUNDLE_SYSTEM_LIBRARIES)
+    if(component_libraries)
+        list(APPEND bundle_system_libraries ${component_libraries})
+    endif()
+    get_target_property(component_pkgconfig ${component}_LIB 
BRPC_PRIVATE_SYSTEM_LIBS)
+    if(component_pkgconfig)
+        list(APPEND component_system_libs "${component_pkgconfig}")
+    endif()
+endforeach()
+list(APPEND DYNAMIC_LIB ${bundle_system_libraries})
+string(JOIN " " BRPC_PRIVATE_LIBS ${component_private_libs} 
${component_system_libs})
+
+target_link_libraries(brpc_bundle_dependencies INTERFACE ${DYNAMIC_LIB})
+# Keep legacy debug tests and pkg-config generation supplied by the bundle.
+set(DYNAMIC_LIB ${DYNAMIC_LIB} PARENT_SCOPE)
+set(BRPC_PRIVATE_LIBS "${BRPC_PRIVATE_LIBS}" PARENT_SCOPE)
 
-# shared library needs POSITION_INDEPENDENT_CODE
-set_property(TARGET ${SOURCES_LIB} PROPERTY POSITION_INDEPENDENT_CODE 1)
-set_property(TARGET ${BUTIL_LIB} PROPERTY POSITION_INDEPENDENT_CODE 1)
+set(BRPC_SOURCE_OBJECTS)
+foreach(component BVAR BTHREAD JSON2PB MCPACK2PB BRPC)
+    list(APPEND BRPC_SOURCE_OBJECTS $<TARGET_OBJECTS:${component}_LIB>)
+endforeach()
 
 add_library(brpc-static STATIC $<TARGET_OBJECTS:BUTIL_LIB>
-                               $<TARGET_OBJECTS:SOURCES_LIB>
+                               ${BRPC_SOURCE_OBJECTS}
                                $<TARGET_OBJECTS:PROTO_LIB>)
-target_link_libraries(brpc-static PUBLIC brpc_common_config)
-
-function(check_thrift_version target_arg)
-    #use thrift command to get version
-    execute_process(
-        COMMAND thrift --version
-        OUTPUT_VARIABLE THRIFT_VERSION_OUTPUT
-        ERROR_QUIET
-        OUTPUT_STRIP_TRAILING_WHITESPACE
-    )
-
-    string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" THRIFT_VERSION 
${THRIFT_VERSION_OUTPUT})
-    string(REGEX REPLACE "\\." ";" THRIFT_VERSION_LIST ${THRIFT_VERSION})
-
-    list(GET THRIFT_VERSION_LIST 0 THRIFT_MAJOR_VERSION)
-    list(GET THRIFT_VERSION_LIST 1 THRIFT_MINOR_VERSION)
-
-    if (THRIFT_MAJOR_VERSION EQUAL 0 AND THRIFT_MINOR_VERSION LESS 11)
-        message(STATUS "Thrift version is less than 0.11.0")
-        target_compile_definitions(${target_arg} PRIVATE 
_THRIFT_VERSION_LOWER_THAN_0_11_0_)
-    else()
-        message(STATUS "Thrift version is equal to or greater than 0.11.0")
-    endif()
-endfunction()
-
-
-if(WITH_THRIFT)
-   target_link_libraries(brpc-static PRIVATE ${THRIFT_LIB})
-   check_thrift_version(brpc-static)
-endif()
+target_link_libraries(brpc-static PUBLIC brpc_build_config)
+target_link_libraries(brpc-static PRIVATE brpc_bundle_dependencies)
 
 SET_TARGET_PROPERTIES(brpc-static PROPERTIES OUTPUT_NAME brpc 
CLEAN_DIRECT_OUTPUT 1)
 
-# for protoc-gen-mcpack
-set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/output/bin)
-    
-set(protoc_gen_mcpack_SOURCES
-    ${PROJECT_SOURCE_DIR}/src/mcpack2pb/generator.cpp
- )
-    
-add_executable(protoc-gen-mcpack ${protoc_gen_mcpack_SOURCES})
-target_link_libraries(protoc-gen-mcpack PRIVATE brpc_common_config)
-
 if(BUILD_SHARED_LIBS)
     add_library(brpc-shared SHARED $<TARGET_OBJECTS:BUTIL_LIB> 
-                                   $<TARGET_OBJECTS:SOURCES_LIB>
+                                   ${BRPC_SOURCE_OBJECTS}
                                    $<TARGET_OBJECTS:PROTO_LIB>)
-    target_link_libraries(brpc-shared PUBLIC brpc_common_config)
-    target_link_libraries(brpc-shared PRIVATE ${DYNAMIC_LIB})
-    if(WITH_GLOG)
-        target_link_libraries(brpc-shared PRIVATE ${GLOG_LIB})
-    endif()
-    if(WITH_THRIFT)
-        target_link_libraries(brpc-shared PRIVATE ${THRIFT_LIB})
-        check_thrift_version(brpc-shared)
-    endif()
+    target_link_libraries(brpc-shared PUBLIC brpc_build_config)
+    target_link_libraries(brpc-shared PRIVATE brpc_bundle_dependencies)
     SET_TARGET_PROPERTIES(brpc-shared PROPERTIES OUTPUT_NAME brpc 
CLEAN_DIRECT_OUTPUT 1)
 
-    target_link_libraries(protoc-gen-mcpack PRIVATE brpc-shared ${DYNAMIC_LIB})
-
     install(TARGETS brpc-shared
             RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
             LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
             ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
             )
-else()
-    target_link_libraries(protoc-gen-mcpack PRIVATE brpc-static ${DYNAMIC_LIB})
 endif()
 
 
diff --git a/src/brpc/CMakeLists.txt b/src/brpc/CMakeLists.txt
new file mode 100644
index 00000000..4efd059b
--- /dev/null
+++ b/src/brpc/CMakeLists.txt
@@ -0,0 +1,345 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set(WITH_RDMA_VAL "0")
+if(WITH_RDMA)
+    set(WITH_RDMA_VAL "1")
+endif()
+
+set(WITH_URMA_VAL "0")
+if(WITH_URMA)
+    set(WITH_URMA_VAL "1")
+endif()
+
+string(TOUPPER "${URMA_USE_MOCK}" URMA_USE_MOCK_MODE)
+if(NOT URMA_USE_MOCK_MODE STREQUAL "AUTO" AND
+   NOT URMA_USE_MOCK_MODE STREQUAL "ON" AND
+   NOT URMA_USE_MOCK_MODE STREQUAL "OFF")
+    message(FATAL_ERROR
+        "URMA_USE_MOCK must be AUTO, ON, or OFF, got: ${URMA_USE_MOCK}")
+endif()
+
+set(WITH_UBRING_VAL "0")
+if(WITH_UBRING)
+        set(WITH_UBRING_VAL "1")
+endif()
+
+set(BRPC_DEFINITIONS
+    BRPC_WITH_RDMA=${WITH_RDMA_VAL}
+    BRPC_WITH_URMA=${WITH_URMA_VAL}
+    BRPC_WITH_UBRING=${WITH_UBRING_VAL})
+set(BRPC_INCLUDE_DIRS)
+if(WITH_THRIFT)
+    list(APPEND BRPC_DEFINITIONS ENABLE_THRIFT_FRAMED_PROTOCOL)
+    find_library(THRIFT_LIB NAMES thrift)
+    if (NOT THRIFT_LIB)
+        message(FATAL_ERROR "Fail to find Thrift")
+    endif()
+endif()
+
+if(WITH_THRIFT)
+    find_path(THRIFT_INCLUDE_PATH NAMES thrift/Thrift.h)
+    if(NOT THRIFT_INCLUDE_PATH)
+        message(FATAL_ERROR "Fail to find Thrift headers")
+    endif()
+    list(APPEND BRPC_INCLUDE_DIRS ${THRIFT_INCLUDE_PATH})
+endif()
+find_package(ZLIB REQUIRED)
+list(APPEND BRPC_INCLUDE_DIRS ${ZLIB_INCLUDE_DIRS})
+
+# Older LevelDB packages reference Threads::Threads without finding it.
+find_package(Threads REQUIRED)
+find_package(leveldb CONFIG QUIET)
+add_library(brpc_leveldb INTERFACE)
+set(brpc_pkgconfig_needs_snappy ${WITH_SNAPPY})
+if(TARGET leveldb::leveldb)
+    # LevelDB 1.23 exports its private -Werror/-Wthread-safety diagnostics.
+    # Filter only these known packaging mistakes from the imported target's
+    # in-memory interface, without editing the installed package.
+    get_target_property(leveldb_compile_options leveldb::leveldb 
INTERFACE_COMPILE_OPTIONS)
+    if(leveldb_compile_options)
+        list(REMOVE_ITEM leveldb_compile_options -Werror -Wthread-safety)
+        set_property(TARGET leveldb::leveldb PROPERTY
+            INTERFACE_COMPILE_OPTIONS "${leveldb_compile_options}")
+    endif()
+    target_link_libraries(brpc_leveldb INTERFACE leveldb::leveldb)
+
+    # The legacy .pc file needs its own representation of the dependency.
+    get_target_property(leveldb_dependencies leveldb::leveldb 
INTERFACE_LINK_LIBRARIES)
+    get_target_property(leveldb_type leveldb::leveldb TYPE)
+    if(leveldb_type STREQUAL "SHARED_LIBRARY" AND leveldb_dependencies)
+        # LevelDB 1.23 also exports bare "snappy" for shared libraries.
+        # The loader resolves that dependency; consumers do not need
+        # Snappy's development library. Keep it for static/unknown library 
types.
+        list(REMOVE_ITEM leveldb_dependencies snappy "$<LINK_ONLY:snappy>")
+        set_property(TARGET leveldb::leveldb PROPERTY
+            INTERFACE_LINK_LIBRARIES "${leveldb_dependencies}")
+    endif()
+    foreach(dependency IN LISTS leveldb_dependencies)
+        if(dependency MATCHES "(^|[:;])([Ss]nappy::)?snappy($|[;>])")
+            set(brpc_pkgconfig_needs_snappy ON)
+        endif()
+        if((dependency STREQUAL "snappy" OR
+            dependency STREQUAL "$<LINK_ONLY:snappy>") AND NOT TARGET snappy)
+            # Old exports use bare "snappy" without finding it or supplying a
+            # search directory. Resolve that link item for non-system prefixes.
+            find_library(SNAPPY_LIB NAMES snappy)
+            if(NOT SNAPPY_LIB)
+                message(FATAL_ERROR "LevelDB requires Snappy, but it was not 
found")
+            endif()
+            add_library(snappy UNKNOWN IMPORTED)
+            set_property(TARGET snappy PROPERTY IMPORTED_LOCATION 
"${SNAPPY_LIB}")
+        endif()
+    endforeach()
+else()
+    # Keep supporting installations without a CMake package configuration.
+    find_path(LEVELDB_INCLUDE_PATH NAMES leveldb/db.h)
+    find_library(LEVELDB_LIB NAMES leveldb)
+    if((NOT LEVELDB_INCLUDE_PATH) OR (NOT LEVELDB_LIB))
+        message(FATAL_ERROR "Fail to find leveldb")
+    endif()
+    target_include_directories(brpc_leveldb SYSTEM INTERFACE 
${LEVELDB_INCLUDE_PATH})
+    target_link_libraries(brpc_leveldb INTERFACE ${LEVELDB_LIB})
+endif()
+if(WITH_SNAPPY)
+    find_library(SNAPPY_LIB NAMES snappy)
+    if(NOT SNAPPY_LIB)
+        message(FATAL_ERROR "Fail to find snappy")
+    endif()
+endif()
+
+if(WITH_RDMA)
+    message("brpc compile with rdma")
+    find_path(RDMA_INCLUDE_PATH NAMES infiniband/verbs.h)
+    find_library(RDMA_LIB NAMES ibverbs)
+    if((NOT RDMA_INCLUDE_PATH) OR (NOT RDMA_LIB))
+        message(FATAL_ERROR "Fail to find ibverbs")
+    endif()
+    list(APPEND BRPC_INCLUDE_DIRS ${RDMA_INCLUDE_PATH})
+endif()
+
+if(WITH_URMA)
+    # UrmaTransport and its link-time mock both compile against the upstream
+    # UMDK API. Prefer installed headers; otherwise fetch a pinned upstream
+    # commit, following Mooncake's URMA mock setup.
+    find_path(URMA_INCLUDE_PATH NAMES urma_api.h
+              HINTS ENV URMA_ROOT
+              PATHS /usr/include /usr/local/include
+              PATH_SUFFIXES ub/umdk/urma umdk/urma urma
+                            src/urma/lib/urma/core/include)
+    find_path(URMA_BOND_INCLUDE_PATH NAMES urma_ubagg.h
+              HINTS ENV URMA_ROOT
+              PATHS /usr/include /usr/local/include
+              PATH_SUFFIXES ub/umdk/urma umdk/urma urma
+                            src/urma/lib/urma/bond/include)
+    if(NOT URMA_INCLUDE_PATH AND DOWNLOAD_URMA_HEADERS)
+        include(FetchContent)
+        FetchContent_Declare(
+            urma_headers
+            GIT_REPOSITORY https://atomgit.com/openeuler/umdk.git
+            GIT_TAG 564ee727a55523d4351a8fb3c94292b388ebb924
+            # brpc only consumes UMDK headers; avoid cloning unrelated UMDK
+            # submodules such as CAM dependencies during configuration.
+            GIT_SUBMODULES ""
+            GIT_SHALLOW TRUE)
+        FetchContent_GetProperties(urma_headers)
+        if(NOT urma_headers_POPULATED)
+            FetchContent_Populate(urma_headers)
+        endif()
+        set(URMA_INCLUDE_PATH
+            "${urma_headers_SOURCE_DIR}/src/urma/lib/urma/core/include")
+        set(URMA_BOND_INCLUDE_PATH
+            "${urma_headers_SOURCE_DIR}/src/urma/lib/urma/bond/include")
+        message(STATUS "Using downloaded UMDK headers: ${URMA_INCLUDE_PATH}")
+    endif()
+    if(NOT URMA_INCLUDE_PATH)
+        message(FATAL_ERROR
+            "Fail to find urma_api.h. Install UMDK headers, set URMA_ROOT, "
+            "or enable DOWNLOAD_URMA_HEADERS.")
+    endif()
+
+    find_library(URMA_LIB NAMES urma
+                 HINTS ENV URMA_ROOT
+                 PATH_SUFFIXES lib lib64)
+    if(URMA_USE_MOCK_MODE STREQUAL "ON")
+        message(STATUS "URMA_USE_MOCK=ON; forcing the link-time URMA mock")
+        set(URMA_USE_MOCK_ENABLED 1)
+    elseif(URMA_USE_MOCK_MODE STREQUAL "OFF")
+        if(NOT URMA_LIB)
+            message(FATAL_ERROR
+                "URMA_USE_MOCK=OFF requires liburma; install it or use 
AUTO/ON.")
+        endif()
+        message(STATUS "URMA_USE_MOCK=OFF; using liburma")
+        set(URMA_USE_MOCK_ENABLED 0)
+    elseif(URMA_LIB)
+        message(STATUS "Found URMA library: ${URMA_LIB}")
+        set(URMA_USE_MOCK_ENABLED 0)
+    else()
+        message(STATUS
+            "liburma not found; building with the URMA link-time mock")
+        set(URMA_USE_MOCK_ENABLED 1)
+    endif()
+endif()
+
+if(WITH_URMA)
+    list(APPEND BRPC_INCLUDE_DIRS ${URMA_INCLUDE_PATH})
+    if(URMA_BOND_INCLUDE_PATH)
+        list(APPEND BRPC_INCLUDE_DIRS ${URMA_BOND_INCLUDE_PATH})
+    endif()
+endif()
+add_library(brpc_build_config INTERFACE)
+target_link_libraries(brpc_build_config INTERFACE bthread_build_config)
+if(WITH_URMA AND URMA_USE_MOCK_ENABLED)
+    # The link-time mock uses std::shared_mutex, which requires C++17.
+    target_compile_features(brpc_build_config INTERFACE cxx_std_17)
+endif()
+target_include_directories(brpc_build_config BEFORE INTERFACE
+    ${CMAKE_CURRENT_BINARY_DIR})
+target_compile_definitions(brpc_build_config INTERFACE ${BRPC_DEFINITIONS})
+target_include_directories(brpc_build_config INTERFACE ${BRPC_INCLUDE_DIRS})
+
+function(check_thrift_version target_arg)
+    #use thrift command to get version
+    execute_process(
+        COMMAND thrift --version
+        OUTPUT_VARIABLE THRIFT_VERSION_OUTPUT
+        ERROR_QUIET
+        OUTPUT_STRIP_TRAILING_WHITESPACE
+    )
+
+    string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" THRIFT_VERSION 
${THRIFT_VERSION_OUTPUT})
+    string(REGEX REPLACE "\\." ";" THRIFT_VERSION_LIST ${THRIFT_VERSION})
+
+    list(GET THRIFT_VERSION_LIST 0 THRIFT_MAJOR_VERSION)
+    list(GET THRIFT_VERSION_LIST 1 THRIFT_MINOR_VERSION)
+
+    if (THRIFT_MAJOR_VERSION EQUAL 0 AND THRIFT_MINOR_VERSION LESS 11)
+        message(STATUS "Thrift version is less than 0.11.0")
+        target_compile_definitions(${target_arg} INTERFACE 
_THRIFT_VERSION_LOWER_THAN_0_11_0_)
+    else()
+        message(STATUS "Thrift version is equal to or greater than 0.11.0")
+    endif()
+endfunction()
+
+if(WITH_THRIFT)
+    check_thrift_version(brpc_build_config)
+endif()
+
+file(GLOB_RECURSE BRPC_SOURCES CONFIGURE_DEPENDS 
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+file(GLOB_RECURSE THRIFT_SOURCES CONFIGURE_DEPENDS 
"${CMAKE_CURRENT_SOURCE_DIR}/thrift*.cpp")
+file(GLOB_RECURSE EXCLUDE_SOURCES CONFIGURE_DEPENDS 
"${CMAKE_CURRENT_SOURCE_DIR}/event_dispatcher_*.cpp")
+
+# When building with the real liburma, exclude the link-time mock so its urma_*
+# symbols do not clash with the library. When liburma is absent, keep it so CI
+# can build and test UrmaTransport without URMA hardware.
+if(WITH_URMA AND NOT URMA_USE_MOCK_ENABLED)
+    list(REMOVE_ITEM BRPC_SOURCES
+         "${CMAKE_CURRENT_SOURCE_DIR}/urma/mock_urma.cpp")
+endif()
+
+if(WITH_THRIFT)
+    message("brpc compile with thrift protocol")
+else()
+    # Remove thrift sources
+    foreach(v ${THRIFT_SOURCES})
+        list(REMOVE_ITEM BRPC_SOURCES ${v})
+    endforeach()
+    set(THRIFT_SOURCES "")
+endif()
+
+foreach(v ${EXCLUDE_SOURCES})
+    list(REMOVE_ITEM BRPC_SOURCES ${v})
+endforeach()
+
+include(CompileProto)
+set(PROTO_FILES brpc/builtin_service.proto
+                brpc/errno.proto
+                brpc/get_favicon.proto
+                brpc/get_js.proto
+                brpc/grpc_health_check.proto
+                brpc/nshead_meta.proto
+                brpc/options.proto
+                brpc/policy/baidu_rpc_meta.proto
+                brpc/policy/hulu_pbrpc_meta.proto
+                brpc/policy/mongo.proto
+                brpc/policy/public_pbrpc_meta.proto
+                brpc/policy/sofa_pbrpc_meta.proto
+                brpc/proto_base.proto
+                brpc/rdma/rdma_handshake.proto
+                brpc/rpc_dump.proto
+                brpc/rtmp.proto
+                brpc/span.proto
+                brpc/streaming_rpc_meta.proto
+                brpc/trackme.proto
+                brpc/urma/urma_handshake.proto
+                idl_options.proto)
+compile_proto(PROTO_HDRS PROTO_SRCS ${CMAKE_CURRENT_BINARY_DIR}
+                                    ${CMAKE_CURRENT_SOURCE_DIR}/..
+                                    "${PROTO_FILES}")
+add_library(PROTO_LIB OBJECT ${PROTO_SRCS} ${PROTO_HDRS})
+set_property(TARGET PROTO_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+target_link_libraries(PROTO_LIB PRIVATE brpc_build_config)
+
+set(brpc_libraries brpc_leveldb)
+set(brpc_private_libs "-lleveldb")
+if(WITH_THRIFT)
+    list(APPEND brpc_libraries ${THRIFT_LIB})
+    string(APPEND brpc_private_libs " -lthrift")
+endif()
+if(WITH_SNAPPY)
+    list(APPEND brpc_libraries ${SNAPPY_LIB})
+endif()
+if(brpc_pkgconfig_needs_snappy)
+    string(APPEND brpc_private_libs " -lsnappy")
+endif()
+if(WITH_RDMA)
+    list(APPEND brpc_libraries ${RDMA_LIB})
+    string(APPEND brpc_private_libs " -libverbs")
+endif()
+if(WITH_URMA)
+    message(STATUS "brpc compile with URMA (mock=${URMA_USE_MOCK_ENABLED})")
+    if(NOT URMA_USE_MOCK_ENABLED)
+        list(APPEND brpc_libraries ${URMA_LIB})
+        string(APPEND brpc_private_libs " -lurma")
+    endif()
+endif()
+if(WITH_UBRING)
+    message(STATUS "brpc compile with ubring")
+    list(APPEND brpc_libraries ${UB_LIB})
+    if(UB_LIB)
+        get_filename_component(ub_name "${UB_LIB}" NAME_WE)
+        string(REGEX REPLACE "^lib|\\..*$" "" ub_name "${ub_name}")
+        string(APPEND brpc_private_libs " -l${ub_name}")
+    endif()
+endif()
+
+add_library(brpc_runtime_dependencies INTERFACE)
+target_link_libraries(brpc_runtime_dependencies INTERFACE ${brpc_libraries})
+add_library(brpc_system_dependencies INTERFACE)
+target_link_libraries(brpc_system_dependencies INTERFACE ZLIB::ZLIB)
+
+add_library(BRPC_LIB OBJECT ${BRPC_SOURCES})
+target_link_libraries(BRPC_LIB PRIVATE brpc_build_config brpc_leveldb)
+set_property(TARGET BRPC_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+set_property(TARGET BRPC_LIB PROPERTY BRPC_BUNDLE_LIBRARIES 
brpc_runtime_dependencies)
+set_property(TARGET BRPC_LIB PROPERTY BRPC_PRIVATE_LIBS "${brpc_private_libs}")
+set_property(TARGET BRPC_LIB PROPERTY BRPC_BUNDLE_SYSTEM_LIBRARIES 
brpc_system_dependencies)
+set_property(TARGET BRPC_LIB PROPERTY BRPC_PRIVATE_SYSTEM_LIBS "-lz")
+add_dependencies(BRPC_LIB PROTO_LIB)
+
+brpc_install_module_headers()
+brpc_install_headers(${CMAKE_CURRENT_BINARY_DIR} ${PROTO_HDRS})
diff --git a/src/bthread/CMakeLists.txt b/src/bthread/CMakeLists.txt
new file mode 100644
index 00000000..813d6b85
--- /dev/null
+++ b/src/bthread/CMakeLists.txt
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set(WITH_DEBUG_LOCK_VAL "0")
+if(WITH_DEBUG_LOCK)
+    set(WITH_DEBUG_LOCK_VAL "1")
+endif()
+
+set(WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL "0")
+if(WITH_DEBUG_BTHREAD_SCHE_SAFETY)
+    set(WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL "1")
+endif()
+
+set(BTHREAD_DEFINITIONS
+    BRPC_DEBUG_LOCK=${WITH_DEBUG_LOCK_VAL}
+    BRPC_DEBUG_BTHREAD_SCHE_SAFETY=${WITH_DEBUG_BTHREAD_SCHE_SAFETY_VAL}
+    BTHREAD_USE_FAST_PTHREAD_MUTEX)
+set(BTHREAD_INCLUDE_DIRS)
+if (WITH_BTHREAD_TRACER)
+    if (NOT (CMAKE_SYSTEM_NAME STREQUAL "Linux")  OR NOT 
(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64"))
+        message(FATAL_ERROR "bthread tracer is only supported on Linux x86_64 
platform")
+    endif()
+    find_path(LIBUNWIND_INCLUDE_PATH NAMES libunwind.h)
+    find_library(LIBUNWIND_LIB NAMES unwind)
+    find_library(LIBUNWIND_X86_64_LIB NAMES unwind-x86_64)
+    if (NOT LIBUNWIND_INCLUDE_PATH OR NOT LIBUNWIND_LIB OR NOT 
LIBUNWIND_X86_64_LIB)
+        message(FATAL_ERROR "Fail to find libunwind, which is needed by 
bthread tracer")
+    endif()
+    find_package(absl REQUIRED CONFIG)
+    set(bthread_tracer_ABSL_USED_TARGETS absl::base absl::stacktrace 
absl::symbolize)
+    list(APPEND BTHREAD_DEFINITIONS BRPC_BTHREAD_TRACER)
+    list(APPEND BTHREAD_INCLUDE_DIRS ${LIBUNWIND_INCLUDE_PATH})
+endif ()
+
+add_library(bthread_build_config INTERFACE)
+target_link_libraries(bthread_build_config INTERFACE butil_build_config)
+target_compile_definitions(bthread_build_config INTERFACE 
${BTHREAD_DEFINITIONS})
+target_include_directories(bthread_build_config INTERFACE 
${BTHREAD_INCLUDE_DIRS})
+
+file(GLOB_RECURSE BTHREAD_SOURCES CONFIGURE_DEPENDS 
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+
+set(bthread_libraries)
+set(bthread_private_libs "")
+if(WITH_BTHREAD_TRACER)
+    list(APPEND bthread_libraries ${bthread_tracer_ABSL_USED_TARGETS}
+        ${LIBUNWIND_X86_64_LIB} ${LIBUNWIND_LIB})
+    set(bthread_private_libs "-labsl_stacktrace -labsl_symbolize 
-labsl_debugging_internal -labsl_demangle_internal -labsl_malloc_internal 
-labsl_base -labsl_spinlock_wait -labsl_raw_logging_internal -lunwind-x86_64 
-lunwind")
+endif()
+
+add_library(bthread_runtime_dependencies INTERFACE)
+target_link_libraries(bthread_runtime_dependencies INTERFACE 
${bthread_libraries})
+
+add_library(BTHREAD_LIB OBJECT ${BTHREAD_SOURCES})
+target_link_libraries(BTHREAD_LIB PRIVATE bthread_build_config)
+set_property(TARGET BTHREAD_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+set_property(TARGET BTHREAD_LIB PROPERTY BRPC_BUNDLE_LIBRARIES 
bthread_runtime_dependencies)
+set_property(TARGET BTHREAD_LIB PROPERTY BRPC_PRIVATE_LIBS 
"${bthread_private_libs}")
+
+brpc_install_module_headers()
diff --git a/src/butil/CMakeLists.txt b/src/butil/CMakeLists.txt
new file mode 100644
index 00000000..1e57710a
--- /dev/null
+++ b/src/butil/CMakeLists.txt
@@ -0,0 +1,298 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set(WITH_GLOG_VAL "0")
+if(WITH_GLOG)
+    set(WITH_GLOG_VAL "1")
+    set(BRPC_WITH_GLOG 1)
+endif()
+
+set(WITH_CPU_FREQUENCY_VAL "0")
+if(WITH_CPU_FREQUENCY)
+    set(WITH_CPU_FREQUENCY_VAL "1")
+    set(BUTIL_USE_CPU_FREQUENCY 1)
+endif()
+
+set(BUTIL_DEFINITIONS
+    BRPC_WITH_GLOG=${WITH_GLOG_VAL}
+    BUTIL_USE_CPU_FREQUENCY=${WITH_CPU_FREQUENCY_VAL})
+if(WITH_MESALINK)
+    list(APPEND BUTIL_DEFINITIONS USE_MESALINK)
+endif()
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+    include(CheckFunctionExists)
+    CHECK_FUNCTION_EXISTS(clock_gettime HAVE_CLOCK_GETTIME)
+    if(NOT HAVE_CLOCK_GETTIME)
+        list(APPEND BUTIL_DEFINITIONS NO_CLOCK_GETTIME_IN_MAC)
+    endif()
+endif()
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
+    ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY)
+get_filename_component(butil_generated_include_dir
+    "${CMAKE_CURRENT_BINARY_DIR}/.." ABSOLUTE)
+
+set(BUTIL_INCLUDE_DIRS ${GFLAGS_INCLUDE_PATH} ${PROTOBUF_INCLUDE_DIRS})
+if(WITH_GLOG)
+    find_path(GLOG_INCLUDE_PATH NAMES glog/logging.h)
+    find_library(GLOG_LIB NAMES glog)
+    if((NOT GLOG_INCLUDE_PATH) OR (NOT GLOG_LIB))
+        message(FATAL_ERROR "Fail to find glog")
+    endif()
+    list(APPEND BUTIL_INCLUDE_DIRS ${GLOG_INCLUDE_PATH})
+endif()
+
+if(WITH_MESALINK)
+    find_path(MESALINK_INCLUDE_PATH NAMES mesalink/openssl/ssl.h)
+    find_library(MESALINK_LIB NAMES mesalink)
+    if((NOT MESALINK_INCLUDE_PATH) OR (NOT MESALINK_LIB))
+        message(FATAL_ERROR "Fail to find MesaLink")
+    else()
+        message(STATUS "Found MesaLink: ${MESALINK_LIB}")
+    endif()
+    list(APPEND BUTIL_INCLUDE_DIRS ${MESALINK_INCLUDE_PATH})
+endif()
+
+if(WITH_BORINGSSL)
+    find_package(BoringSSL REQUIRED)
+    list(APPEND BUTIL_INCLUDE_DIRS ${BORINGSSL_INCLUDE_DIR})
+else()
+    if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT OPENSSL_ROOT_DIR)
+        set(OPENSSL_ROOT_DIR
+            "/usr/local/opt/openssl" # Homebrew installed OpenSSL
+        )
+    endif()
+
+    find_package(OpenSSL REQUIRED)
+    list(APPEND BUTIL_INCLUDE_DIRS ${OPENSSL_INCLUDE_DIR})
+endif()
+
+add_library(butil_build_config INTERFACE)
+target_link_libraries(butil_build_config INTERFACE brpc_common_config)
+target_compile_definitions(butil_build_config INTERFACE ${BUTIL_DEFINITIONS})
+target_include_directories(butil_build_config BEFORE INTERFACE
+    ${butil_generated_include_dir})
+target_include_directories(butil_build_config INTERFACE ${BUTIL_INCLUDE_DIRS})
+
+set(butil_crc32c_options)
+if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+    if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
+        # Only CRC32C needs the SSE4.2 intrinsics and feature macro.
+        list(APPEND butil_crc32c_options -msse4.2)
+    endif()
+endif()
+if(butil_crc32c_options)
+    set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/crc32c.cc
+        APPEND PROPERTY COMPILE_OPTIONS ${butil_crc32c_options})
+endif()
+
+# the reason why not using file(GLOB_RECURSE...) is that we want to
+# include different files on different platforms.
+set(BUTIL_SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/arena.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/at_exit.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/atomicops_internals_x86_gcc.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/base64.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/base64url.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/big_endian.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/binary_printer.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/class_name.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/containers/case_ignored_flat_map.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/cpu.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/crc32c.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/alias.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/asan_invalid_access.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/crash_logging.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/debugger.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/debugger_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/dump_without_crashing.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/proc_maps_linux.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/stack_trace.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/debug/stack_trace_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/endpoint.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/environment.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/errno.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/fast_rand.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/fd_utility.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_util.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_util_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file_enumerator.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file_enumerator_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file_path.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file_path_constants.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/file_watcher.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/memory_mapped_file.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/memory_mapped_file_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/scoped_file.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/scoped_temp_dir.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/files/temp_file.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/find_cstr.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/guid.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/guid_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/hash.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/iobuf.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/iobuf_profiler.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/lazy_instance.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/location.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/logging.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/memory/aligned_memory.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/memory/ref_counted.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/memory/ref_counted_memory.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/memory/singleton.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/memory/weak_ptr.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/popen.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/posix/file_descriptor_shuffle.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/posix/global_descriptors.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/process_util.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/rand_util.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/rand_util_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/recordio.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/safe_strerror_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/sha1_portable.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/single_iobuf.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/status.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_compare_rvv.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_printf.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/latin1_string_conversions.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/nullable_string16.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/safe_sprintf.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/string16.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/string_number_conversions.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/string_piece.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/string_split.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/string_util.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/string_util_constants.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/stringprintf.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/utf_offset_string_conversions.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/utf_string_conversion_utils.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/strings/utf_string_conversions.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/synchronization/cancellation_flag.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/synchronization/condition_variable_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/synchronization/waitable_event_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/dmg_fp/dtoa_wrapper.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/dmg_fp/g_fmt.cc
+    
${CMAKE_CURRENT_SOURCE_DIR}/third_party/dynamic_annotations/dynamic_annotations.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/icu/icu_utf.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/modp_b64/modp_b64.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/modp_b64/modp_b64_rvv.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/murmurhash3/murmurhash3.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/snappy/snappy-sinksource.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/snappy/snappy-stubs-internal.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/snappy/snappy.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/superfasthash/superfasthash.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/symbolize/demangle.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/third_party/symbolize/symbolize.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_key.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_local.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/non_thread_safe_impl.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/platform_thread_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/simple_thread.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_checker_impl.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_collision_warner.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_id_name_manager.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_local_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_local_storage.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_local_storage_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/thread_restrictions.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/threading/watchdog.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/time/clock.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time/default_clock.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time/default_tick_clock.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time/tick_clock.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time/time.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time/time_posix.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/unix_socket.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/version.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/zero_copy_stream_as_streambuf.cpp
+    )
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+set(BUTIL_SOURCES ${BUTIL_SOURCES}
+        ${CMAKE_CURRENT_SOURCE_DIR}/file_util_linux.cc
+        ${CMAKE_CURRENT_SOURCE_DIR}/strings/sys_string_conversions_posix.cc
+        ${CMAKE_CURRENT_SOURCE_DIR}/threading/platform_thread_linux.cc)
+elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+set(BUTIL_SOURCES ${BUTIL_SOURCES}
+        ${CMAKE_CURRENT_SOURCE_DIR}/file_util_mac.mm
+        ${CMAKE_CURRENT_SOURCE_DIR}/mac/bundle_locations.mm
+        ${CMAKE_CURRENT_SOURCE_DIR}/mac/foundation_util.mm
+        ${CMAKE_CURRENT_SOURCE_DIR}/mac/scoped_mach_port.cc
+        ${CMAKE_CURRENT_SOURCE_DIR}/strings/sys_string_conversions_mac.mm
+        ${CMAKE_CURRENT_SOURCE_DIR}/threading/platform_thread_mac.mm
+        ${CMAKE_CURRENT_SOURCE_DIR}/time/time_mac.cc)
+endif()
+
+set(butil_platform_libraries)
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+    set(butil_platform_libraries
+        pthread
+        "-framework CoreFoundation"
+        "-framework CoreGraphics"
+        "-framework CoreData"
+        "-framework CoreText"
+        "-framework Security"
+        "-framework Foundation"
+        "-Wl,-U,_MallocExtension_ReleaseFreeMemory"
+        "-Wl,-U,_ProfilerStart"
+        "-Wl,-U,_ProfilerStop"
+        "-Wl,-U,__Z13GetStackTracePPvii"
+        "-Wl,-U,_mallctl"
+        "-Wl,-U,_malloc_stats_print"
+    )
+endif()
+
+set(butil_libraries ${GFLAGS_LIBRARY} protobuf::libprotobuf
+    ${protobuf_ABSL_USED_TARGETS})
+set(butil_system_libraries ${CMAKE_THREAD_LIBS_INIT} dl 
${butil_platform_libraries})
+set(butil_private_libs "-lgflags -lprotobuf")
+set(butil_private_system_libs "-ldl")
+if(CMAKE_THREAD_LIBS_INIT)
+    string(APPEND butil_private_system_libs " ${CMAKE_THREAD_LIBS_INIT}")
+endif()
+if(WITH_BORINGSSL)
+    list(APPEND butil_libraries ${BORINGSSL_SSL_LIBRARY} 
${BORINGSSL_CRYPTO_LIBRARY})
+    string(APPEND butil_private_libs " -lssl -lcrypto")
+elseif(WITH_MESALINK)
+    list(APPEND butil_libraries ${MESALINK_LIB} ${OPENSSL_CRYPTO_LIBRARY})
+    string(APPEND butil_private_libs " -lmesalink -lcrypto")
+else()
+    list(APPEND butil_libraries ${OPENSSL_SSL_LIBRARY} 
${OPENSSL_CRYPTO_LIBRARY})
+    string(APPEND butil_private_libs " -lssl -lcrypto")
+endif()
+if(WITH_GLOG)
+    list(PREPEND butil_libraries ${GLOG_LIB})
+    set(butil_private_libs "-lglog ${butil_private_libs}")
+endif()
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+    list(APPEND butil_system_libraries rt)
+    string(APPEND butil_private_system_libs " -lrt")
+endif()
+
+add_library(BUTIL_LIB OBJECT ${BUTIL_SOURCES})
+target_link_libraries(BUTIL_LIB PRIVATE butil_build_config)
+set_property(TARGET BUTIL_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+set_property(TARGET BUTIL_LIB PROPERTY BRPC_CRC32C_COMPILE_OPTIONS 
"${butil_crc32c_options}")
+set_property(TARGET BUTIL_LIB PROPERTY BRPC_BUNDLE_LIBRARIES 
"${butil_libraries}")
+set_property(TARGET BUTIL_LIB PROPERTY BRPC_PRIVATE_LIBS 
"${butil_private_libs}")
+set_property(TARGET BUTIL_LIB PROPERTY BRPC_BUNDLE_SYSTEM_LIBRARIES 
"${butil_system_libraries}")
+set_property(TARGET BUTIL_LIB PROPERTY BRPC_PRIVATE_SYSTEM_LIBS 
"${butil_private_system_libs}")
+
+brpc_install_module_headers()
+brpc_install_headers(${butil_generated_include_dir} 
${CMAKE_CURRENT_BINARY_DIR}/config.h)
diff --git a/config.h.in b/src/butil/config.h.in
similarity index 100%
rename from config.h.in
rename to src/butil/config.h.in
diff --git a/tools/trackme_server/CMakeLists.txt b/src/bvar/CMakeLists.txt
similarity index 73%
copy from tools/trackme_server/CMakeLists.txt
copy to src/bvar/CMakeLists.txt
index ca40e419..ac8176d9 100644
--- a/tools/trackme_server/CMakeLists.txt
+++ b/src/bvar/CMakeLists.txt
@@ -15,6 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
-add_executable(trackme_server trackme_server.cpp)
-target_link_libraries(trackme_server PRIVATE brpc-static ${DYNAMIC_LIB})
-install(TARGETS trackme_server RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+file(GLOB_RECURSE BVAR_SOURCES CONFIGURE_DEPENDS 
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+
+add_library(BVAR_LIB OBJECT ${BVAR_SOURCES})
+target_link_libraries(BVAR_LIB PRIVATE butil_build_config)
+set_property(TARGET BVAR_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+
+brpc_install_module_headers()
diff --git a/tools/trackme_server/CMakeLists.txt b/src/json2pb/CMakeLists.txt
similarity index 72%
copy from tools/trackme_server/CMakeLists.txt
copy to src/json2pb/CMakeLists.txt
index ca40e419..24f085d5 100644
--- a/tools/trackme_server/CMakeLists.txt
+++ b/src/json2pb/CMakeLists.txt
@@ -15,6 +15,10 @@
 # specific language governing permissions and limitations
 # under the License.
 
-add_executable(trackme_server trackme_server.cpp)
-target_link_libraries(trackme_server PRIVATE brpc-static ${DYNAMIC_LIB})
-install(TARGETS trackme_server RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+file(GLOB_RECURSE JSON2PB_SOURCES CONFIGURE_DEPENDS 
"${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
+
+add_library(JSON2PB_LIB OBJECT ${JSON2PB_SOURCES})
+target_link_libraries(JSON2PB_LIB PRIVATE butil_build_config)
+set_property(TARGET JSON2PB_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+
+brpc_install_module_headers()
diff --git a/src/mcpack2pb/CMakeLists.txt b/src/mcpack2pb/CMakeLists.txt
new file mode 100644
index 00000000..a038aac1
--- /dev/null
+++ b/src/mcpack2pb/CMakeLists.txt
@@ -0,0 +1,50 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set(MCPACK2PB_SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/field_type.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/mcpack2pb.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/parser.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/serializer.cpp)
+
+add_library(MCPACK2PB_LIB OBJECT ${MCPACK2PB_SOURCES})
+target_link_libraries(MCPACK2PB_LIB PRIVATE butil_build_config)
+set_property(TARGET MCPACK2PB_LIB PROPERTY POSITION_INDEPENDENT_CODE 1)
+
+if(TARGET protobuf::libprotoc)
+    set(PROTOC_LIB protobuf::libprotoc)
+else()
+    find_library(PROTOC_LIB NAMES protoc)
+endif()
+if(NOT PROTOC_LIB)
+    message(FATAL_ERROR "Fail to find protoc lib")
+endif()
+
+# Legacy bundles/tests retain protoc linkage; the runtime component does not.
+set_property(TARGET MCPACK2PB_LIB PROPERTY BRPC_BUNDLE_LIBRARIES 
"${PROTOC_LIB}")
+set_property(TARGET MCPACK2PB_LIB PROPERTY BRPC_PRIVATE_LIBS "-lprotoc")
+
+add_executable(protoc-gen-mcpack generator.cpp)
+set_target_properties(protoc-gen-mcpack PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/output/bin)
+if(BUILD_SHARED_LIBS)
+    target_link_libraries(protoc-gen-mcpack PRIVATE brpc-shared 
brpc_bundle_dependencies)
+else()
+    target_link_libraries(protoc-gen-mcpack PRIVATE brpc-static)
+endif()
+
+brpc_install_module_headers()
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 71baf85d..a0fc2d05 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -15,10 +15,14 @@
 # specific language governing permissions and limitations
 # under the License.
 
+if(BUILD_FUZZ_TESTS AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    message(FATAL_ERROR "Fuzzing is only supported with clang")
+endif()
+
 find_package(Gperftools)
 
 add_library(brpc_test_config INTERFACE)
-target_link_libraries(brpc_test_config INTERFACE brpc_common_config)
+target_link_libraries(brpc_test_config INTERFACE brpc_build_config)
 target_include_directories(brpc_test_config INTERFACE 
${CMAKE_CURRENT_BINARY_DIR})
 target_compile_definitions(brpc_test_config INTERFACE
     UNIT_TEST
@@ -30,25 +34,23 @@ if(GPERFTOOLS_INCLUDE_DIR)
 endif()
 
 include(CompileProto)
-set(TEST_PROTO_FILES addressbook1.proto
+set(TEST_PROTO_FILES addressbook.proto
+                     addressbook1.proto
                      addressbook_encode_decode.proto
                      addressbook_map.proto
-                     addressbook.proto
                      echo.proto
+                     grpc.proto
+                     health_check.proto
                      iobuf.proto
                      message.proto
                      repeated.proto
                      snappy_message.proto
                      v1.proto
                      v2.proto
-                     v3.proto
-                     grpc.proto
-                     health_check.proto)
-file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/test/hdrs)
+                     v3.proto)
 set(PROTOC_FLAGS ${PROTOC_FLAGS} -I${CMAKE_SOURCE_DIR}/src)
-compile_proto(PROTO_HDRS PROTO_SRCS ${CMAKE_BINARY_DIR}/test
-                                    ${CMAKE_BINARY_DIR}/test/hdrs
-                                    ${CMAKE_SOURCE_DIR}/test
+compile_proto(PROTO_HDRS PROTO_SRCS ${CMAKE_CURRENT_BINARY_DIR}
+                                    ${CMAKE_CURRENT_SOURCE_DIR}
                                     "${TEST_PROTO_FILES}")
 add_library(TEST_PROTO_LIB OBJECT ${PROTO_SRCS} ${PROTO_HDRS})
 target_link_libraries(TEST_PROTO_LIB PRIVATE brpc_test_config)
@@ -72,123 +74,123 @@ else()
     message(FATAL_ERROR "Googletest is not available")
 endif()
 
-file(COPY ${PROJECT_SOURCE_DIR}/test/cert1.key DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/test/cert2.key DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/test/cert1.crt DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/test/cert2.crt DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/test/jsonout DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
-file(COPY ${PROJECT_SOURCE_DIR}/test/run_tests.sh DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/cert1.key DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/cert2.key DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/cert1.crt DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/cert2.crt DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/jsonout DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
+file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/run_tests.sh DESTINATION 
${CMAKE_CURRENT_BINARY_DIR})
 
 SET(TEST_BUTIL_SOURCES
-    ${PROJECT_SOURCE_DIR}/test/recordio_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/popen_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/bounded_queue_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/at_exit_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/atomicops_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/base64_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/base64url_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/big_endian_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/bits_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/hash_tables_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/linked_list_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/mru_cache_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/small_map_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/stack_container_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/mpsc_queue_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/cpu_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/crash_logging_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/leak_tracker_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/stack_trace_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/environment_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/file_util_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/dir_reader_posix_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/file_path_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/file_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/scoped_temp_dir_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/guid_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/hash_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/lazy_instance_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/aligned_memory_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/linked_ptr_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/ref_counted_memory_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/ref_counted_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/scoped_ptr_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/scoped_vector_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/singleton_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/weak_ptr_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/observer_list_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/file_descriptor_shuffle_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/rand_util_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/safe_numerics_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/scoped_clear_errno_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/scoped_generic_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/security_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/sha1_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/stl_util_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/nullable_string16_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/safe_sprintf_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/string16_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/stringprintf_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/string_number_conversions_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/string_piece_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/string_split_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/string_tokenizer_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/string_util_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/stringize_macros_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/sys_string_conversions_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/utf_offset_string_conversions_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/utf_string_conversions_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/cancellation_flag_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/condition_variable_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/lock_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/waitable_event_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/type_traits_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/non_thread_safe_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/platform_thread_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/simple_thread_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/thread_checker_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/thread_collision_warner_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/thread_id_name_manager_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/thread_local_storage_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/thread_local_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/abalist_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/watchdog_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/time_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/version_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/logging_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/cacheline_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/class_name_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/endpoint_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/unique_ptr_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/errno_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/fd_guard_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/file_watcher_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/find_cstr_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/scoped_lock_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/status_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/string_printf_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/string_splitter_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/synchronous_event_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/temp_file_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/baidu_thread_local_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/thread_key_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/baidu_time_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/flat_map_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/crc32c_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/iobuf_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/object_pool_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/test_switches.cc
-    ${PROJECT_SOURCE_DIR}/test/scoped_locale.cc
-    ${PROJECT_SOURCE_DIR}/test/scope_guard_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/optional_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/seqlock_unittest.cpp
-    ${PROJECT_SOURCE_DIR}/test/butil_unittest_main.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/abalist_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/aligned_memory_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/at_exit_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/atomicops_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/baidu_thread_local_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/baidu_time_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/base64_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/base64url_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/big_endian_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/bits_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/bounded_queue_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/butil_unittest_main.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/cacheline_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/cancellation_flag_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/class_name_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/condition_variable_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/cpu_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/crash_logging_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/crc32c_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/dir_reader_posix_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/endpoint_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/environment_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/errno_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/fd_guard_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_descriptor_shuffle_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_path_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_util_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/file_watcher_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/find_cstr_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/flat_map_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/guid_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/hash_tables_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/hash_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/iobuf_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/lazy_instance_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/leak_tracker_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/linked_list_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/linked_ptr_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/lock_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/logging_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/mpsc_queue_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/mru_cache_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/non_thread_safe_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/nullable_string16_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/object_pool_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/observer_list_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/optional_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/platform_thread_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/popen_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/rand_util_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/recordio_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/ref_counted_memory_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/ref_counted_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/safe_numerics_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/safe_sprintf_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/scope_guard_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_clear_errno_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_generic_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_locale.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_lock_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_ptr_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_temp_dir_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/scoped_vector_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/security_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/seqlock_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/sha1_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/simple_thread_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/singleton_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/small_map_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/stack_container_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/stack_trace_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/status_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/stl_util_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string16_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_number_conversions_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_piece_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_printf_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_split_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_splitter_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_tokenizer_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/string_util_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/stringize_macros_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/stringprintf_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/synchronous_event_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/sys_string_conversions_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/temp_file_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/test_switches.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_checker_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_collision_warner_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_id_name_manager_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_key_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_local_storage_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/thread_local_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/time_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/type_traits_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/unique_ptr_unittest.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/utf_offset_string_conversions_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/utf_string_conversions_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/version_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/waitable_event_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/watchdog_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/weak_ptr_unittest.cc
        )
 
 if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
 SET(TEST_BUTIL_SOURCES ${TEST_BUTIL_SOURCES}
-    ${PROJECT_SOURCE_DIR}/test/proc_maps_linux_unittest.cc
-    ${PROJECT_SOURCE_DIR}/test/test_file_util_linux.cc)
+    ${CMAKE_CURRENT_SOURCE_DIR}/proc_maps_linux_unittest.cc
+    ${CMAKE_CURRENT_SOURCE_DIR}/test_file_util_linux.cc)
 endif()
 
 # bthread_* functions are used in logging.cc, and they need to be marked as
@@ -202,11 +204,26 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
     )
 endif()
 
+# Read module-owned sources from their targets, not parent-scope variables.
+get_target_property(BUTIL_SOURCES BUTIL_LIB SOURCES)
+# Source properties are directory-scoped; reuse production CRC32C settings.
+get_target_property(butil_crc32c_options BUTIL_LIB BRPC_CRC32C_COMPILE_OPTIONS)
+if(butil_crc32c_options)
+    set_property(SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/../src/butil/crc32c.cc
+        APPEND PROPERTY COMPILE_OPTIONS ${butil_crc32c_options})
+endif()
+get_target_property(BVAR_SOURCES BVAR_LIB SOURCES)
+set(SOURCES)
+foreach(component BVAR BTHREAD JSON2PB MCPACK2PB BRPC)
+    get_target_property(component_sources ${component}_LIB SOURCES)
+    list(APPEND SOURCES ${component_sources})
+endforeach()
+
 add_library(BUTIL_DEBUG_LIB OBJECT ${BUTIL_SOURCES})
 add_library(SOURCES_DEBUG_LIB OBJECT ${SOURCES})
 add_dependencies(SOURCES_DEBUG_LIB PROTO_LIB)
 target_link_libraries(BUTIL_DEBUG_LIB PRIVATE brpc_test_config)
-target_link_libraries(SOURCES_DEBUG_LIB PRIVATE brpc_test_config)
+target_link_libraries(SOURCES_DEBUG_LIB PRIVATE brpc_test_config brpc_leveldb)
 
 # shared library needs POSITION_INDEPENDENT_CODE
 set_property(TARGET ${BUTIL_DEBUG_LIB} PROPERTY POSITION_INDEPENDENT_CODE 1)
@@ -220,9 +237,6 @@ set_target_properties(brpc-shared-debug PROPERTIES
          LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/test)
 
 target_link_libraries(brpc-shared-debug PUBLIC brpc_test_config ${DYNAMIC_LIB})
-if(BRPC_WITH_GLOG)
-    target_link_libraries(brpc-shared-debug PUBLIC ${GLOG_LIB})
-endif()
 
 # AddressSanitizer is incompatible with tcmalloc/gperftools, do not link it 
when WITH_ASAN is on
 if(WITH_ASAN)
@@ -241,7 +255,9 @@ add_test(NAME test_butil COMMAND test_butil)
 
 # test_bvar
 # -DBVAR_NOT_LINK_DEFAULT_VARIABLES not work for gcc >= 5.0, just remove the 
file to prevent linking into unit tests
-list(REMOVE_ITEM BVAR_SOURCES 
${PROJECT_SOURCE_DIR}/src/bvar/default_variables.cpp)
+get_filename_component(bvar_default_variables
+    "${CMAKE_CURRENT_SOURCE_DIR}/../src/bvar/default_variables.cpp" ABSOLUTE)
+list(REMOVE_ITEM BVAR_SOURCES ${bvar_default_variables})
 
 add_library(BVAR_DEBUG_LIB OBJECT ${BVAR_SOURCES})
 target_link_libraries(BVAR_DEBUG_LIB PRIVATE brpc_test_config)
@@ -290,9 +306,6 @@ if(BUILD_FUZZ_TESTS)
             LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/test)
 
     target_link_libraries(brpc-static-debug PUBLIC brpc_test_config 
${DYNAMIC_LIB})
-    if(BRPC_WITH_GLOG)
-        target_link_libraries(brpc-static-debug PUBLIC ${GLOG_LIB})
-    endif()
 
     set(FUZZ_TARGETS fuzz_butil fuzz_esp fuzz_hpack fuzz_http
         fuzz_hulu fuzz_json fuzz_redis fuzz_shead fuzz_sofa fuzz_uri
diff --git a/test/cmake_link_dependencies/CMakeLists.txt 
b/test/cmake_link_dependencies/CMakeLists.txt
new file mode 100644
index 00000000..098f52fa
--- /dev/null
+++ b/test/cmake_link_dependencies/CMakeLists.txt
@@ -0,0 +1,37 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+add_executable(cmake_bundle_link_check consumer.cpp)
+# Do not add DYNAMIC_LIB here: that would hide missing bundle dependencies.
+target_link_libraries(cmake_bundle_link_check PRIVATE brpc-static)
+add_executable(cmake_logging_link_check logging.cpp)
+target_link_libraries(cmake_logging_link_check PRIVATE brpc-static)
+add_executable(cmake_leveldb_link_check leveldb.cpp)
+target_link_libraries(cmake_leveldb_link_check PRIVATE brpc_leveldb)
+
+add_custom_target(cmake_link_checks
+    COMMAND ${CMAKE_COMMAND}
+        -DPKGCONFIG_FILE=${PROJECT_BINARY_DIR}/brpc.pc
+        -DWITH_GLOG=${WITH_GLOG} -DWITH_THRIFT=${WITH_THRIFT}
+        -DWITH_SNAPPY=${WITH_SNAPPY} -DWITH_RDMA=${WITH_RDMA}
+        -DWITH_MESALINK=${WITH_MESALINK}
+        -P ${CMAKE_CURRENT_SOURCE_DIR}/check_pkgconfig.cmake
+    COMMAND $<TARGET_FILE:cmake_bundle_link_check>
+    COMMAND $<TARGET_FILE:cmake_logging_link_check>
+    COMMAND $<TARGET_FILE:cmake_leveldb_link_check>
+    DEPENDS cmake_bundle_link_check cmake_logging_link_check 
cmake_leveldb_link_check
+    VERBATIM)
diff --git a/test/cmake_link_dependencies/check_pkgconfig.cmake 
b/test/cmake_link_dependencies/check_pkgconfig.cmake
new file mode 100644
index 00000000..658dd9c0
--- /dev/null
+++ b/test/cmake_link_dependencies/check_pkgconfig.cmake
@@ -0,0 +1,72 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+cmake_minimum_required(VERSION 3.16)
+file(READ "${PKGCONFIG_FILE}" metadata)
+if(NOT metadata MATCHES "\nLibs.private: ([^\n]*)")
+    message(FATAL_ERROR "Missing private dependency metadata")
+endif()
+separate_arguments(libraries UNIX_COMMAND "${CMAKE_MATCH_1}")
+foreach(required -lprotoc -lleveldb -lgflags -lprotobuf -lcrypto -lz -ldl)
+    if(NOT required IN_LIST libraries)
+        message(FATAL_ERROR "Missing ${required} in Libs.private")
+    endif()
+endforeach()
+
+function(require_order consumer provider)
+    list(FIND libraries "${consumer}" consumer_index)
+    list(FIND libraries "${provider}" provider_index)
+    if(NOT consumer_index EQUAL -1 AND NOT provider_index EQUAL -1 AND
+       NOT consumer_index LESS provider_index)
+        message(FATAL_ERROR "${consumer} must precede ${provider}: 
${libraries}")
+    endif()
+endfunction()
+
+function(require_optional option library)
+    list(FIND libraries "${library}" index)
+    if(${option})
+        if(index EQUAL -1)
+            message(FATAL_ERROR "${option} requires ${library}")
+        endif()
+    elseif(NOT index EQUAL -1)
+        message(FATAL_ERROR "${option}=OFF must not require ${library}")
+    endif()
+endfunction()
+
+require_optional(WITH_GLOG -lglog)
+require_optional(WITH_THRIFT -lthrift)
+# Snappy can also be a dependency of the selected LevelDB package.
+if(WITH_SNAPPY AND NOT "-lsnappy" IN_LIST libraries)
+    message(FATAL_ERROR "WITH_SNAPPY requires -lsnappy")
+endif()
+require_optional(WITH_RDMA -libverbs)
+require_optional(WITH_MESALINK -lmesalink)
+require_order(-lglog -lgflags)
+require_order(-lprotoc -lprotobuf)
+require_order(-lleveldb -lsnappy)
+require_order(-lssl -lcrypto)
+require_order(-lmesalink -lcrypto)
+require_order(-lssl -lz)
+require_order(-lcrypto -lz)
+require_order(-lprotobuf -lz)
+require_order(-lthrift -lssl)
+require_order(-labsl_stacktrace -lunwind)
+require_order(-labsl_malloc_internal -labsl_base)
+require_order(-labsl_base -labsl_spinlock_wait)
+require_order(-labsl_base -labsl_raw_logging_internal)
+require_order(-lunwind-x86_64 -lunwind)
+require_order(-lunwind -ldl)
diff --git a/test/cmake_link_dependencies/consumer.cpp 
b/test/cmake_link_dependencies/consumer.cpp
new file mode 100644
index 00000000..f9fef64b
--- /dev/null
+++ b/test/cmake_link_dependencies/consumer.cpp
@@ -0,0 +1,43 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <string>
+#include <google/protobuf/compiler/command_line_interface.h>
+#include "brpc/controller.h"
+#include "butil/iobuf.h"
+#include "butil/logging.h"
+#ifdef ENABLE_THRIFT_FRAMED_PROTOCOL
+#include <thrift/TApplicationException.h>
+#endif
+
+int main() {
+    LOG(INFO) << "Check the bundle's transitive link dependencies";
+    google::protobuf::compiler::CommandLineInterface compiler;
+    compiler.AllowPlugins("protoc-");
+    brpc::Controller controller;
+    butil::IOBuf buffer;
+    if (buffer.append("link check") != 0 || controller.Failed()) {
+        return 1;
+    }
+#ifdef ENABLE_THRIFT_FRAMED_PROTOCOL
+    apache::thrift::TApplicationException exception("link check");
+    if (std::string(exception.what()).find("link check") == std::string::npos) 
{
+        return 1;
+    }
+#endif
+    return buffer.to_string() != "link check";
+}
diff --git a/test/cmake_link_dependencies/leveldb.cpp 
b/test/cmake_link_dependencies/leveldb.cpp
new file mode 100644
index 00000000..fbd1f6f5
--- /dev/null
+++ b/test/cmake_link_dependencies/leveldb.cpp
@@ -0,0 +1,25 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include <leveldb/db.h>
+
+int main() {
+    // Retain a DB implementation reference to exercise static dependencies
+    // without opening a database or touching the filesystem.
+    auto* volatile open_database = &leveldb::DB::Open;
+    return open_database == nullptr;
+}
diff --git a/test/cmake_link_dependencies/logging.cpp 
b/test/cmake_link_dependencies/logging.cpp
new file mode 100644
index 00000000..4828a621
--- /dev/null
+++ b/test/cmake_link_dependencies/logging.cpp
@@ -0,0 +1,23 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "butil/logging.h"
+
+int main() {
+    LOG(INFO) << "Check static logging dependencies";
+    return 0;
+}
diff --git a/tools/parallel_http/CMakeLists.txt 
b/tools/parallel_http/CMakeLists.txt
index 69676444..a06f5c87 100644
--- a/tools/parallel_http/CMakeLists.txt
+++ b/tools/parallel_http/CMakeLists.txt
@@ -16,5 +16,5 @@
 # under the License.
 
 add_executable(parallel_http parallel_http.cpp)
-target_link_libraries(parallel_http PRIVATE brpc-static ${DYNAMIC_LIB})
+target_link_libraries(parallel_http PRIVATE brpc-static)
 install(TARGETS parallel_http RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/tools/rpc_press/CMakeLists.txt b/tools/rpc_press/CMakeLists.txt
index 762d3466..12ea1d95 100644
--- a/tools/rpc_press/CMakeLists.txt
+++ b/tools/rpc_press/CMakeLists.txt
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-file(GLOB SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/tools/rpc_press/*.cpp")
+file(GLOB SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
 add_executable(rpc_press ${SOURCES})
-target_link_libraries(rpc_press PRIVATE brpc-static ${DYNAMIC_LIB})
+target_link_libraries(rpc_press PRIVATE brpc-static)
 install(TARGETS rpc_press RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/tools/rpc_replay/CMakeLists.txt b/tools/rpc_replay/CMakeLists.txt
index f1a55abd..0da4bd34 100644
--- a/tools/rpc_replay/CMakeLists.txt
+++ b/tools/rpc_replay/CMakeLists.txt
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-file(GLOB SOURCES CONFIGURE_DEPENDS 
"${PROJECT_SOURCE_DIR}/tools/rpc_replay/*.cpp")
+file(GLOB SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp")
 add_executable(rpc_replay ${SOURCES})
-target_link_libraries(rpc_replay PRIVATE brpc-static ${DYNAMIC_LIB})
+target_link_libraries(rpc_replay PRIVATE brpc-static)
 install(TARGETS rpc_replay RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/tools/rpc_view/CMakeLists.txt b/tools/rpc_view/CMakeLists.txt
index 1fe67014..82734ba4 100644
--- a/tools/rpc_view/CMakeLists.txt
+++ b/tools/rpc_view/CMakeLists.txt
@@ -20,5 +20,5 @@ protobuf_generate_cpp(PROTO_SRC PROTO_HEADER view.proto)
 
 add_executable(rpc_view rpc_view.cpp ${PROTO_SRC})
 target_include_directories(rpc_view PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
-target_link_libraries(rpc_view PRIVATE brpc-static ${DYNAMIC_LIB})
+target_link_libraries(rpc_view PRIVATE brpc-static)
 install(TARGETS rpc_view RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/tools/trackme_server/CMakeLists.txt 
b/tools/trackme_server/CMakeLists.txt
index ca40e419..2325bbd3 100644
--- a/tools/trackme_server/CMakeLists.txt
+++ b/tools/trackme_server/CMakeLists.txt
@@ -16,5 +16,5 @@
 # under the License.
 
 add_executable(trackme_server trackme_server.cpp)
-target_link_libraries(trackme_server PRIVATE brpc-static ${DYNAMIC_LIB})
+target_link_libraries(trackme_server PRIVATE brpc-static)
 install(TARGETS trackme_server RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to