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

如何通过CMake配置实现多库同名头文件的命名空间引入

解决同名头文件的CMake配置方案

我有两个(或更多)包含同名头文件(比如utils.h)的库,在项目里需要不同场景下使用这些头文件里的类,但常规引入方式因为文件名歧义无法正确引入目标文件。很多库通过给头文件添加命名空间路径(比如#include <rapidjson/document.h>)解决这个问题,我想实现这个方案,请问怎么用CMake配置?

以下是我当前的相关CMake配置代码:

主项目GISManager的CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(GISManager LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(OSMManager REQUIRED) #First libray
find_package(GeoJSONParser REQUIRED) #Second library

set(GISManager_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(GISManager_H ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(Hdrs ${GISManager_H}/gismanager.h )
set(Srcs ${GISManager_SRC}/gismanager.cpp)

add_library(GISManager ${Hdrs} ${Srcs})
target_include_directories(GISManager PUBLIC
    $<BUILD_INTERFACE:${GISManager_H}/>
    ${OSMManager_INCLUDE_DIRS}/
    ${GeoJSONParser_INCLUDE_DIRS}/
)
target_link_libraries(GISManager ${OSMManager_LIBRARIES} ${GeoJSONParser_LIBRARIES})

add_executable(GISManager_Test ${Hdrs} ${Srcs} ${GISManager_SRC}/main.cpp)
target_include_directories(GISManager_Test PUBLIC
    $<BUILD_INTERFACE:${GISManager_H}/>
    ${OSMManager_INCLUDE_DIRS}/
    ${GeoJSONParser_INCLUDE_DIRS}/
)
target_link_libraries(GISManager_Test ${OSMManager_LIBRARIES} ${GeoJSONParser_LIBRARIES})

install(FILES  ${Hdrs}  DESTINATION include/GISManager-${version})
install(TARGETS GISManager
        DESTINATION lib/GISManager-${version}
        EXPORT GISManager-targets)
install(EXPORT GISManager-targets
        DESTINATION lib/GISManager-${version})

configure_file(
   ${GISManager_SOURCE_DIR}/pkg/gismanager-config.cmake.in
   ${GISManager_BINARY_DIR}/pkg/gismanager-config.cmake @ONLY)

configure_file(
   ${GISManager_SOURCE_DIR}/pkg/gismanager-config-version.cmake.in
   ${GISManager_BINARY_DIR}/pkg/gismanager-config-version.cmake @ONLY)

install(FILES ${GISManager_BINARY_DIR}/pkg/gismanager-config.cmake
         ${GISManager_BINARY_DIR}/pkg/gismanager-config-version.cmake
         DESTINATION lib/GISManager-${version})

GeoJSONParser库的CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(GeoJSONParser LANGUAGES CXX)
set(version 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(GeoJSONParser_H ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(GeoJSONParser_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)
find_path(RapidJSON_INCLUDE_DIRS rapidjson)


set(HDRS
    ${GeoJSONParser_H}/object.h
    ${GeoJSONParser_H}/featurecollection.h
    ${GeoJSONParser_H}/feature.h
    ${GeoJSONParser_H}/geometry.h
    ${GeoJSONParser_H}/point.h
    ${GeoJSONParser_H}/multipoint.h
    ${GeoJSONParser_H}/linestring.h
    ${GeoJSONParser_H}/multilinestring.h
    ${GeoJSONParser_H}/polygon.h
    ${GeoJSONParser_H}/multipolygon.h
    ${GeoJSONParser_H}/geometrycollection.h
    ${GeoJSONParser_H}/utils.h
    ${GeoJSONParser_H}/types.h
)
set(SRCS
    ${GeoJSONParser_SRC}/featurecollection.cpp
    ${GeoJSONParser_SRC}/feature.cpp
    ${GeoJSONParser_SRC}/point.cpp
    ${GeoJSONParser_SRC}/multipoint.cpp
    ${GeoJSONParser_SRC}/linestring.cpp
    ${GeoJSONParser_SRC}/multilinestring.cpp
    ${GeoJSONParser_SRC}/polygon.cpp
    ${GeoJSONParser_SRC}/multipolygon.cpp
    ${GeoJSONParser_SRC}/geometrycollection.cpp
    ${GeoJSONParser_SRC}/utils.cpp
)

add_library(GeoJSONParser ${HDRS} ${SRCS})
target_include_directories(GeoJSONParser PUBLIC $<BUILD_INTERFACE:${GeoJSONParser_H}/> ${RapidJSON_INCLUDE_DIRS})

add_executable(GeoJSONParser_Test ${HDRS} ${SRCS} ${GeoJSONParser_SRC}/main.cpp)
target_include_directories(GeoJSONParser_Test PUBLIC $<BUILD_INTERFACE:${GeoJSONParser_H}/> ${RapidJSON_INCLUDE_DIRS})

install(FILES  ${HDRS}  DESTINATION include/GeoJSONParser-${version})
install(TARGETS GeoJSONParser
        DESTINATION lib/GeoJSONParser-${version}
        EXPORT GeoJSONParser-targets)
install(EXPORT GeoJSONParser-targets
        DESTINATION lib/GeoJSONParser-${version})

configure_file(
   ${GeoJSONParser_SOURCE_DIR}/pkg/geojsonparser-config.cmake.in
   ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config.cmake @ONLY)

configure_file(
   ${GeoJSONParser_SOURCE_DIR}/pkg/geojsonparser-config-version.cmake.in
   ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config-version.cmake @ONLY)

install(FILES ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config.cmake
         ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config-version.cmake
         DESTINATION lib/GeoJSONParser-${version})

OSMManager库的CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(OSMManager LANGUAGES CXX)
set(version 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(OSMManager_H ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(OSMManager_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)
find_path(RapidJSON_INCLUDE_DIRS rapidjson)
find_package(PROJ)

set(HDRS
    ${OSMManager_H}/root.h
    ${OSMManager_H}/node.h
    ${OSMManager_H}/way.h
    ${OSMManager_H}/relation.h
    ${OSMManager_H}/coordinatesconverter.h
    ${OSMManager_H}/utils.h
    ${OSMManager_H}/types.h
    ${OSMManager_H}/tinyxml2.h
)
set(SRCS
    ${OSMManager_SRC}/root.cpp
    ${OSMManager_SRC}/node.cpp
    ${OSMManager_SRC}/way.cpp
    ${OSMManager_SRC}/relation.cpp
    ${OSMManager_SRC}/coordinatesconverter.cpp
    ${OSMManager_SRC}/tinyxml2.cpp
)

add_library(OSMManager ${HDRS} ${SRCS})
target_include_directories(OSMManager PUBLIC $<BUILD_INTERFACE:${OSMManager_H}/> ${RapidJSON_INCLUDE_DIRS} ${PROJ_INCLUDE_DIRS})
target_link_libraries(OSMManager ${PROJ_LIBRARIES})

add_executable(OSMManager_Test ${HDRS} ${SRCS} ${OSMManager_SRC}/main.cpp)
target_include_directories(OSMManager_Test PUBLIC $<BUILD_INTERFACE:${OSMManager_H}/> ${RapidJSON_INCLUDE_DIRS} ${PROJ_INCLUDE_DIRS})
target_link_libraries(OSMManager_Test ${PROJ_LIBRARIES})

install(FILES ${HDRS} DESTINATION include/OSMManager-${version})
install(TARGETS OSMManager
        DESTINATION lib/OSMManager-${version}
        EXPORT OSMManager-targets)
install(EXPORT OSMManager-targets
        DESTINATION lib/OSMManager-${version})

configure_file(
   ${OSMManager_SOURCE_DIR}/pkg/osmmanager-config.cmake.in
   ${OSMManager_BINARY_DIR}/pkg/osmmanager-config.cmake @ONLY)

configure_file(
   ${OSMManager_SOURCE_DIR}/pkg/osmmanager-config-version.cmake.in
   ${OSMManager_BINARY_DIR}/pkg/osmmanager-config-version.cmake @ONLY)

install(FILES ${OSMManager_BINARY_DIR}/pkg/osmmanager-config.cmake
         ${OSMManager_BINARY_DIR}/pkg/osmmanager-config-version.cmake
         DESTINATION lib/OSMManager-${version})

GeoJSONParser的config.cmake.in

# Compute installation prefix relative to this file.
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_prefix "${_dir}/../.." ABSOLUTE)

# Import the targets.
include("${_prefix}/lib/GeoJSONParser-@version@/GeoJSONParser-targets.cmake")

# Report other information.
set(GeoJSONParser_INCLUDE_DIRS "${_prefix}/include/GeoJSONParser-@version@/")

file(GLOB GeoJSONParser_LIBRARIES "${_prefix}/lib/GeoJSONParser-@version@/lib*")

解决方案

1. 调整库的目录结构

把每个库的头文件放到与库名同名的子目录下,形成如下结构:

# GeoJSONParser目录结构
GeoJSONParser/
├── include/
│   └── GeoJSONParser/  # 新增子目录,和库名一致
│       ├── object.h
│       ├── featurecollection.h
│       ├── ...
│       └── utils.h
└── src/

# OSMManager目录结构
OSMManager/
├── include/
│   └── OSMManager/  # 新增子目录,和库名一致
│       ├── root.h
│       ├── node.h
│       ├── ...
│       └── utils.h
└── src/

2. 修改库的CMakeLists.txt配置

以GeoJSONParser为例,修改后的配置如下:

cmake_minimum_required(VERSION 3.5)

project(GeoJSONParser LANGUAGES CXX)
set(version 1.0)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# 头文件根目录指向include,而非include/GeoJSONParser
set(GeoJSONParser_H ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(GeoJSONParser_SRC ${CMAKE_CURRENT_SOURCE_DIR}/src)
find_path(RapidJSON_INCLUDE_DIRS rapidjson)

# 更新头文件路径到子目录下
set(HDRS
    ${GeoJSONParser_H}/GeoJSONParser/object.h
    ${GeoJSONParser_H}/GeoJSONParser/featurecollection.h
    ${GeoJSONParser_H}/GeoJSONParser/feature.h
    ${GeoJSONParser_H}/GeoJSONParser/geometry.h
    ${GeoJSONParser_H}/GeoJSONParser/point.h
    ${GeoJSONParser_H}/GeoJSONParser/multipoint.h
    ${GeoJSONParser_H}/GeoJSONParser/linestring.h
    ${GeoJSONParser_H}/GeoJSONParser/multilinestring.h
    ${GeoJSONParser_H}/GeoJSONParser/polygon.h
    ${GeoJSONParser_H}/GeoJSONParser/multipolygon.h
    ${GeoJSONParser_H}/GeoJSONParser/geometrycollection.h
    ${GeoJSONParser_H}/GeoJSONParser/utils.h
    ${GeoJSONParser_H}/GeoJSONParser/types.h
)
set(SRCS
    ${GeoJSONParser_SRC}/featurecollection.cpp
    ${GeoJSONParser_SRC}/feature.cpp
    ${GeoJSONParser_SRC}/point.cpp
    ${GeoJSONParser_SRC}/multipoint.cpp
    ${GeoJSONParser_SRC}/linestring.cpp
    ${GeoJSONParser_SRC}/multilinestring.cpp
    ${GeoJSONParser_SRC}/polygon.cpp
    ${GeoJSONParser_SRC}/multipolygon.cpp
    ${GeoJSONParser_SRC}/geometrycollection.cpp
    ${GeoJSONParser_SRC}/utils.cpp
)

add_library(GeoJSONParser ${HDRS} ${SRCS})
# 设置头文件搜索根目录,编译时指向本地include,安装后指向系统include
target_include_directories(GeoJSONParser PUBLIC 
    $<BUILD_INTERFACE:${GeoJSONParser_H}> 
    $<INSTALL_INTERFACE:include>
    ${RapidJSON_INCLUDE_DIRS}
)

add_executable(GeoJSONParser_Test ${HDRS} ${SRCS} ${GeoJSONParser_SRC}/main.cpp)
target_include_directories(GeoJSONParser_Test PUBLIC 
    $<BUILD_INTERFACE:${GeoJSONParser_H}> 
    ${RapidJSON_INCLUDE_DIRS}
)

# 安装时保留子目录结构,直接安装整个GeoJSONParser目录到include下
install(DIRECTORY ${GeoJSONParser_H}/GeoJSONParser
        DESTINATION include)
install(TARGETS GeoJSONParser
        DESTINATION lib/GeoJSONParser-${version}
        EXPORT GeoJSONParser-targets)
install(EXPORT GeoJSONParser-targets
        DESTINATION lib/GeoJSONParser-${version})

configure_file(
   ${GeoJSONParser_SOURCE_DIR}/pkg/geojsonparser-config.cmake.in
   ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config.cmake @ONLY)

configure_file(
   ${GeoJSONParser_SOURCE_DIR}/pkg/geojsonparser-config-version.cmake.in
   ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config-version.cmake @ONLY)

install(FILES ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config.cmake
         ${GeoJSONParser_BINARY_DIR}/pkg/geojsonparser-config-version.cmake
         DESTINATION lib/GeoJSONParser-${version})

OSMManager的CMakeLists.txt做同样修改:

  • 更新头文件路径到include/OSMManager/xxx.h
  • 调整target_include_directories添加$<INSTALL_INTERFACE:include>
  • 用install(DIRECTORY ${OSMManager_H}/OSMManager DESTINATION include)代替原有的install(FILES)

3. 修改库的config.cmake.in文件

以GeoJSONParser为例,修改后的配置如下:

# Compute installation prefix relative to this file.
get_filename_component(_dir "${CMAKE_CURRENT_LIST_FILE}" PATH)
get_filename_component(_prefix "${_dir}/../.." ABSOLUTE)

# Import the targets.
include("${_prefix}/lib/GeoJSONParser-@version@/GeoJSONParser-targets.cmake")

# Report other information.
# 现在INCLUDE_DIRS指向include根目录,而非子目录
set(GeoJSONParser_INCLUDE_DIRS "${_prefix}/include")

file(GLOB GeoJSONParser_LIBRARIES "${_prefix}/lib/GeoJSONParser-@version@/lib*")

OSMManager的config.cmake.in做同样修改:将OSMManager_INCLUDE_DIRS设置为"${_prefix}/include"。

4. 主项目代码中的引入方式

现在可以像rapidjson那样,通过库名前缀区分同名头文件:

// 引入GeoJSONParser的utils.h
#include <GeoJSONParser/utils.h>
// 引入OSMManager的utils.h
#include <OSMManager/utils.h>

主项目的CMakeLists.txt无需修改,因为库的config文件已经提供了正确的头文件搜索路径。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 23:10:27