当前位置: 首页 > news >正文

CMake简单使用(二)

目录

  • 五、scope 作用域
    • 5.1 作用域的类型
      • 5.1.1 全局作用域
      • 5.1.2 目录作用域
      • 5.1.3 函数作用域
  • 六、宏
    • 6.1 基本语法
    • 6.2 演示代码
  • 七、CMake构建项目
    • 7.1 全局变量
    • 7.2 写入源码路径
    • 7.3 调用子目录cmake脚本
    • 7.4 CMakeLists 嵌套(最常用)
  • 八、CMake 与库
    • 8.1 CMake生成动静态库
      • 8.1.1 动静态库
      • 8.1.2 常见命令
      • 8.1.3 生成静态库
        • 8.1.3.1 示例
        • 8.1.3.2 总结
      • 8.1.4 生成动态库
    • 8.2 CMake调用动静态库
    • 8.2.1 静态库调用流程:
    • 8.2.2 动态库调用流程:

五、scope 作用域

5.1 作用域的类型

5.1.1 全局作用域

  • 从CMake脚本开始运行到结束。
  • 所有CMakeLists.txt文件共享全局作用域
  • 通过set()定义的变量默认是全局变量(除非明确在函数或宏中设置为局部变量)
set(GLOBAL_VAR "I am global")
message(${GLOBAL_VAR}) # 输出: I am global

5.1.2 目录作用域

  • 每个目录中的CMakeLists.txt文件有独立的作用域
  • 子目录可以继承父目录的变量,但子目录中对变量的更改不会影响父目录,只在子目录下生效
    下面是一个demo,理解即可,暂时不尝试自己编译:
# 顶层 CMakeLists.txt
set(DIR_VAR "Parent Directory")
# 添加子目录
add_subdirectory(subdir)
# 子目录 subdir/CMakeLists.txt
message(${DIR_VAR}) # 输出: Parent Directory
set(DIR_VAR "Child Directory")

子目录进行set操作后,顶层的 DIR_VAR 不会被子目录的更改影响。

5.1.3 函数作用域

  • 在函数中定义的变量是局部变量,只在函数内有效
  • 使用set()定义变量时,作用域局限于当前函数,除非指定PARENT_SCOPE
function(set_local_var)set(LOCAL_VAR "Local Scope")message(${LOCAL_VAR}) # 输出: Local Scope
endfunction()set_local_var()
message(${LOCAL_VAR}) # 输出: (空,因为超出函数作用域)

六、宏

6.1 基本语法

macro(<name> [arg1 [arg2 ...]])# 宏体
endmacro()
  • <name> 是宏的名称。
  • [arg1, arg2…] 是参数列表(可选)。
  • 宏没有返回值,但可以通过变量或 CACHE 修改全局状态。

6.2 演示代码

cmake_minimum_required(VERSION 3.20.0)macro(Test myVar)set(myVar "new value")message ("2. argument: ${myVar}")
endmacro()set(myVar "First value")
message ("1. myVar: ${myVar}")
Test("value")
message("3. myVar: ${myVar}")

在这里插入图片描述
在这里插入图片描述

七、CMake构建项目

7.1 全局变量

在[[#1.2 初体验]]中,我们使用了以下代码:

project(hello CXX)
  • 声明项目名称为 hello,并设置主要语言为 C++(CXX)。
  • 生成项目相关的全局变量,例如:
    • ${PROJECT_NAME}:值为 hello
    • ${PROJECT_SOURCE_DIR}:项目的根目录路径。
    • ${PROJECT_BINARY_DIR}:构建目录路径。

7.2 写入源码路径

特点

  • 最简单的构建方式。
  • 适用于只有一个 CMakeLists.txt 文件的小型项目。
    目录结构
MyProject/
├── CMakeLists.txt
├── main.cpp
├──Transportation├──train.h├──tarin.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.20.0)project(MyProject CXX)
add_executable(MyProject main.cpp 需要链接的文件路径)
  • CXX 表示语言是 cpp
  • 在原文件中,要写对应的.h文件,main.cpp:#include "Transportation/train.h",在这里就不需要再包含,但是要包含.cpp文件的路径
    构建方法
cmake -B build
cmake --build build
build/项目名称

![[IMG-20241212140631676.png]]

7.3 调用子目录cmake脚本

  • include方法可以引入子目录中的cmake后缀的配置文件
  • 将配置加入 add_executable
    目录结构:
.
├── CMakeLists.txt
├── main.cpp
└── Transportation├── car.cpp├── car.h├── train.cpp├── train.h└── transportation.cmake

transportation.cmake使用set将变量设置成需要链接的文件:

set(trans_sources Transportation/car.cpp Transportation/train.cpp)

然后在CMakeLists.txt中就可以直接使用该变量:

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)
include(Transportation/transportation.cmake)
add_executable(MyProject main.cpp ${trans_sources})

❗️注意:要使用include引入子目录下的cmake文件,使用变量要用${}
构建方法同上。

7.4 CMakeLists 嵌套(最常用)

  • target_include_directories 头文件目录的声明
  • target_link_libraries 连接库文件
  • add_subdirectory 添加子目录
  • add_ library 生成库文件(默认静态库)
    目录结构:
.
├── CMakeLists.txt
├── main.cpp
└── Transportation├── car.cpp├── car.h├── CMakeLists.txt├── train.cpp└── train.h

在子目录的CMakeLists.txt中,add_library 命令创建一个名为 Translib 的库,该库包含 train.cpp 和 car.cpp 两个源文件的编译结果。

add_library(Translib train.cpp car.cpp)

在父目录的CMakeLists.txt中,

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)add_subdirectory(Transportation)add_executable(MyApp main.cpp)target_link_libraries(MyApp PUBLIC Translib)target_include_directories(MyApp PUBLIC "${PROJECT_SOURCE_DIR}/Transportation")
  1. 定义项目
  • project(MyProject CXX) 声明项目的名称为 MyProject,并设置其主要语言为 C++。
  1. 添加子目录
  • add_subdirectory(Transportation) 将 Transportation 子目录的构建逻辑纳入父目录中。
  • 这会递归执行 Transportation 目录中的 CMakeLists.txt,构建 Translib 库。
  1. 添加可执行文件
  • add_executable(MyApp main.cpp) 声明一个名为 MyApp 的可执行目标,其源文件为 main.cpp。
  1. 链接库
  • target_link_libraries(MyApp PUBLIC Translib) 将 Translib 库链接到可执行文件 MyApp。
  • PUBLIC:表示 Translib 的头文件路径和链接库信息都对 MyProject 和其使用者可见。
  1. 包含头文件路径
  • target_include_directories(MyApp PUBLIC "${PROJECT_SOURCE_DIR}/Transportation") 明确告诉 CMake,MyProject 需要包含 Transportation 目录中的头文件(如 car.h 和 train.h),这样在main.cpp中包含头文件时就不需要再次包含路径。
    构建顺序总结
  1. 进入父目录的构建流程
  • cmake 检测到 add_subdirectory(Transportation),递归构建子目录。
  • 子目录生成 Translib 库。
  1. 构建父目录目标
  • 构建 main.cpp 并将其链接到已生成的 Translib。

八、CMake 与库

8.1 CMake生成动静态库

8.1.1 动静态库

静态库
常见命名:.a(Linux/Unix),.lib(Windows)。

在链接阶段,将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。
对函数库的链接是编译器的链接器在编译阶段完成静态链接的过程

动态库
常见命名:.so(Linux/Unix),.dll(Windows),.dylib(macOS

动态库是在程序运行时才会被载入到内存,当执行到库中代码时就会跳转到目标库。
动态库需要依赖操作系统的动态链接机制

8.1.2 常见命令

  • file(GLOB ...) 常用于搜索源文件
  • add_library(animal STATIC ${SRC}) 生成静态库
  • add_library(animal SHARED ${SRC}) 生成动态库
  • ${LIBRARY_OUTER_PATH} 导出目录

8.1.3 生成静态库

8.1.3.1 示例

当前目录结构如下:

.
├── CMakeLists.txt
├── include
│   ├── car.h
│   └── train.h
└── src├── car.cpp└── train.cpp

CMakeLists.txt:

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)file(GLOB SRC &${PROJECT_SOURCE_DIR}/src/*.cpp)
include_directories(${PROJECT_SOURCE_DIR}/include) set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/a)
add_library(trans STATIC ${SRC})

下面来解释一下上面的代码:

project(MyProject CXX)

在[[#7.1 全局变量]]中,我们了解到使用project时,除声明项目名称外,还会生成项目相关的全局变量,例如:

  • ${PROJECT_NAME}:值为 MyProject。
  • ${PROJECT_SOURCE_DIR}:项目的根目录路径。
  • ${PROJECT_BINARY_DIR}:构建目录路径。

file(GLOB SRC ${PROJECT_SOURCE_DIR}/src/*.cpp)

作用

  • 使用 file(GLOB ...) 命令,搜索 src 目录下所有以 .cpp 结尾的文件,并将它们的路径存入变量 SRC
  • GLOB 是 CMake 提供的文件搜索命令,用于匹配文件路径。
  • 示例:如果 src 目录下有 car.cpp 和 train.cpp,那么 SRC 的值将是:
/path/to/src/car.cpp
/path/to/src/train.cpp

include_directories(${PROJECT_SOURCE_DIR}/include) 

作用

  • 将 include 目录(即 car.h 和 train.h 所在目录)添加到项目的头文件搜索路径中。
  • 等效于将 -I/path/to/include 传递给编译器。
  • 这样,源文件中可以直接使用,而无需写完整路径:
#include "car.h"
#include "train.h"

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/a)

作用

  • 指定生成的库文件的输出目录为项目根目录下的 a 子目录。
  • 如果没有这一行,CMake 默认将库文件输出到构建目录中。

add_library(trans STATIC ${SRC})

作用

  • 定义一个名为 trans 的静态库(STATIC)。
  • SRC 中列出的源文件(如 car.cpp 和 train.cpp)将被编译,并打包成静态库。
8.1.3.2 总结

生成静态库的基本步骤:

# 1. 设置 CMake 最低版本
cmake_minimum_required(VERSION 3.20)
# 2. 定义项目名称和语言
project(MyStaticLibrary LANGUAGES CXX)# 3. 添加头文件路径
include_directories(${PROJECT_SOURCE_DIR}/include)
# 4. 查找源文件
file(GLOB SRC_FILES ${PROJECT_SOURCE_DIR}/src/*.cpp)# 5. 设置库文件的输出路径
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/a)# 6. 添加静态库 声明一个静态库目标(STATIC 表示静态库),指定构成静态库的源文件。
add_library(MyStaticLib STATIC ${SRC_FILES})

8.1.4 生成动态库

生成动态库与生成静态库的步骤类似,只需要将添加静态库的STATIC改为SHARED(动态库也叫共享库)

set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/so)
add_library(trans SHARED ${SRC})

8.2 CMake调用动静态库

8.2.1 静态库调用流程:

  1. 指定静态库的路径
  2. 添加可执行文件
  3. 链接静态库
  4. 添加库的头文件路径
    假设当前目录如下:
flash@VM-12-10-ubuntu:~/2024/12/14_cmake/useLib$ tree -L 2
.
├── CMakeLists.txt
├── include
│   ├── car.h
│   └── train.h
├── Lib
│   ├── libtrans.a
│   └── libtrans.so
└── main.cpp

如果已经生成了动静态库,可以直接删除src目录,但是建议保留include目录,下面来看CMakeLists.txt的具体编写:

cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)# 指定静态库的路径
set(STATIC_LIB_PATH ${PROJECT_SOURCE_DIR}/Lib/libtrans.a)
# 添加可执行文件
add_executable(MyExecutable main.cpp)
# 链接静态库(仅作用于 MyExecutable)
target_link_libraries(MyExecutable PRIVATE ${STATIC_LIB_PATH})
# 添加库的头文件路径(仅作用于 MyExecutable)
target_include_directories(MyExecutable PRIVATE ${PROJECT_SOURCE_DIR}/include)

8.2.2 动态库调用流程:

  1. 指定动态库的路径
  2. 添加可执行文件
  3. 链接静态库
  4. 添加库的头文件路径
cmake_minimum_required(VERSION 3.20.0)
project(MyProject CXX)# 指定动态库的路径
set(DYNAMIC_LIB_PATH ${PROJECT_SOURCE_DIR}/Lib/libtrans.so)
# 添加可执行文件
add_executable(MyExecutable main.cpp)
# 链接动态库(仅作用于 MyExecutable)
target_link_libraries(MyExecutable PRIVATE ${DYNAMIC_LIB_PATH})
# 添加库的头文件路径(仅作用于 MyExecutable)
target_include_directories(MyExecutable PRIVATE ${PROJECT_SOURCE_DIR}/include)

相关文章:

CMake简单使用(二)

目录 五、scope 作用域5.1 作用域的类型5.1.1 全局作用域5.1.2 目录作用域5.1.3 函数作用域 六、宏6.1 基本语法6.2 演示代码 七、CMake构建项目7.1 全局变量7.2 写入源码路径7.3 调用子目录cmake脚本7.4 CMakeLists 嵌套(最常用) 八、CMake 与库8.1 CMake生成动静态库8.1.1 动…...

攻防世界安卓刷题笔记(新手模式)1-4

1.基础android 进入后是这样的页面。查看源代码看看。首先要注意这个软件并没有加壳&#xff0c;所以我们可以直接着手分析。搜索错误提示“Failed”定位到关键代码&#xff0c;看样子就是检验输入的内容 注意到这里有一行关键代码&#xff0c;cond_39对应的正是failed那个地方…...

发现一个对话框中的按钮,全部失效,点击都没有任何反应,已经解决

前端问题&#xff0c;技术vue2&#xff0c;ts。 发现一个对话框中的按钮&#xff0c;全部失效&#xff0c;点击都没有任何反应。 因为我只在template标签中加入下面这个代码&#xff0c;并没有注册。 只要有一个子组件没有注册&#xff0c;就会影响所有的按钮&#xff0c;使当前…...

MyBatisPlus实现多表查询

在MyBatisPlus中实现多表查询&#xff0c;主要有以下几种方法&#xff1a; 使用注解进行多表查询&#xff1a; 你可以在Mapper接口中使用Select注解来编写SQL查询语句&#xff0c;实现多表查询。例如&#xff0c;如果你想根据用户ID查询用户信息和对应的区域名称&#xff0c;可…...

机器学习详解(5):MLP代码详解之MNIST手写数字识别

文章目录 1 MNIST数据集2 代码详解2.1 导入库和GPU2.2 MNIST数据集处理2.2.1 下载和导入2.2.2 张量(Tensors)2.2.3 准备训练数据 2.3 创建模型2.3.1 图像展开2.3.2 输入层2.3.3 隐藏层2.3.4 输出层2.3.5 模型编译 2.4 训练模型2.4.1 损失函数与优化器2.4.2 计算准确率2.4.3 训练…...

如何在vue中实现父子通信

1.需要用到的组件 父组件 <template><div id"app"><BaseCount :count"count" changeCount"cahngeCount"></BaseCount></div> </template><script> import BaseCount from ./components/BaseCount.v…...

PHP实现华为OBS存储

一&#xff1a;华为OBS存储文档地址 官方文档&#xff1a;https://support.huaweicloud.com/obs/index.html github地址&#xff1a;https://github.com/huaweicloud/huaweicloud-sdk-php-obs 二&#xff1a;安装华为OBS拓展 composer require obs/esdk-obs-php 三&#x…...

嵌入式 linux Git常用命令 抽补丁 打补丁

Git常用命令 为什么要学习git呢&#xff1f;我相信刚入门的小伙伴敲打肯定碰到过这种玄学问题&#xff0c;我明明刚刚还能用的代码&#xff0c;后面不知道咋的就不能用了&#xff0c;所以每次你调出一个功能点以后都会手动复制一份代码防止出问题&#xff0c;时间一长发现整个…...

Alan Chhabra:MongoDB AI应用程序计划(MAAP) 为客户提供价值

MongoDB全球合作伙伴执行副总裁 Alan Chhabra 每当有人向我问询MongoDB&#xff0c;我都会说他们很可能在不觉之间已经与MongoDB有过交集。事实上&#xff0c;包括70%财富百强在内的许多世界领先企业公司都在使用MongoDB。我们在MongoDB所做的一切都是为了服务客户&#xff0c…...

【学习笔记】目前市面中手持激光雷达设备及参数汇总

手持激光雷达设备介绍 手持激光雷达设备是一种利用激光时间飞行原理来测量物体距离并构建三维模型的便携式高科技产品。它通过发射激光束并分析反射回来的激光信号&#xff0c;能够精确地获取物体的三维结构信息。这种设备以其高精度、适应各种光照环境的能力和便携性&#xf…...

Burp与小程序梦中情缘

前言 在日常渗透工作中&#xff0c;有时需要对微信小程序进行抓包渗透&#xff0c;通过抓包&#xff0c;我们可以捕获小程序与服务器之间的通信数据&#xff0c;分析这些数据可以帮助我们发现潜在的安全漏洞&#xff0c;本文通过讲述三个方法在PC端来对小程序抓包渗透 文章目…...

数据结构:Win32 API详解

目录 一.Win32 API的介绍 二.控制台程序(Console)与COORD 1..控制台程序(Console): 2.控制台窗口坐标COORD&#xff1a; 3.GetStdHandle函数&#xff1a; &#xff08;1&#xff09;语法&#xff1a; &#xff08;2&#xff09;参数&#xff1a; 4.GetConsoleCursorInf…...

迁移学习中模型训练加速(以mllm模型为例),提速15%以上

根据模型训练过程的显存占用实测的分析,一个1g参数的模型(存储占用4g)训练大约需要20g的显存,其中梯度值占用的显存约一半。博主本意是想实现在迁移学习(冻结部分参数)中模型显存占用的降低,结果不太满意,只能实现训练速度提升,但无法实现显存占用优化。预计是在现有的…...

socket编程UDP-实现停等机制(接收确认、超时重传)

在下面博客中&#xff0c;我介绍了利用UDP模拟TCP连接、按数据包发送文件的过程&#xff0c;并附上完整源码。 socket编程UDP-文件传输&模拟TCP建立连接脱离连接&#xff08;进阶篇&#xff09;_udp socket发送-CSDN博客 下面博客实现的是滑动窗口机制&#xff1a; sock…...

前端面试题目 (Node.JS-Express框架)[二]

在 Express 中如何使用 Passport.js 进行身份认证? Passport.js 是一个 Node.js 的身份验证中间件&#xff0c;它可以很容易地与 Express 集成。下面是一个简单的示例&#xff0c;展示了如何使用 Passport.js 进行基本的身份认证。 安装依赖 npm install express passport …...

防范TCP攻击:策略与实践

TCP&#xff08;传输控制协议&#xff09;是互联网通信的核心协议之一&#xff0c;它确保了数据在网络上的可靠传输。然而&#xff0c;TCP也容易成为各种网络攻击的目标&#xff0c;如SYN洪水攻击、TCP连接耗尽攻击等。本文将探讨如何通过配置防火墙规则、优化服务器设置以及采…...

3D 生成重建034-NerfDiff借助扩散模型直接生成nerf

3D 生成重建034-NerfDiff借助扩散模型直接生成nerf 文章目录 0 论文工作1 论文方法2 实验结果 0 论文工作 感觉这个论文可能能shapE差不多同时期工作&#xff0c;但是shapE是生成任意种类。 本文提出了一种新颖的单图像视图合成方法NerfDiff&#xff0c;该方法利用神经辐射场 …...

分布式 Paxos算法 总结

前言 相关系列 《分布式 & 目录》《分布式 & Paxos算法 & 总结》《分布式 & Paxos算法 & 问题》 参考文献 《图解超难理解的 Paxos 算法&#xff08;含伪代码&#xff09;》《【超详细】分布式一致性协议 - Paxos》 Basic-Paxos 基础帕克索斯算法…...

我的宝贵经验

在技术的浩瀚海洋中&#xff0c;一份优秀的技术文档宛如精准的航海图。它是知识传承的载体&#xff0c;是团队协作的桥梁&#xff0c;更是产品成功的幕后英雄。然而&#xff0c;打造这样一份出色的技术文档并非易事。你是否在为如何清晰阐释复杂技术而苦恼&#xff1f;是否纠结…...

geoserver 瓦片地图,tomcat和nginx实现负载均衡

在地理信息系统&#xff08;GIS&#xff09;领域&#xff0c;GeoServer作为一个强大的开源服务器&#xff0c;能够发布各种地图服务&#xff0c;包括瓦片地图服务。为了提高服务的可用性和扩展性&#xff0c;结合Tomcat和Nginx实现负载均衡成为了一个有效的解决方案。本文将详细…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

条件运算符

C中的三目运算符&#xff08;也称条件运算符&#xff0c;英文&#xff1a;ternary operator&#xff09;是一种简洁的条件选择语句&#xff0c;语法如下&#xff1a; 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true&#xff0c;则整个表达式的结果为“表达式1”…...

【磁盘】每天掌握一个Linux命令 - iostat

目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat&#xff08;I/O Statistics&#xff09;是Linux系统下用于监视系统输入输出设备和CPU使…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...