用【Makefile】或【Cmake】编译【C/Fortran】程序文件
一、vimrc文件设置
set tabstop=4 "tab空格4
set expandtab "将tab扩展成空格
set softtabstop=4 "表示在编辑模式下按退格键时候退回缩进的长度
set shiftwidth=4 "每一级缩进是4个空格
set number "显示行号
filetype plugin on "Makefile空格 set fileencodings=utf-8,ucs-bom,gbk,cp936,gb2312,gb18030 "文件编码
"将.cuf文件用fortran的语法高亮配置进行高亮显示
au BufRead,BufNewFile *.cuf set filetype=fortran if has("persistent_undo")
let target_path = expand('~/.vim/undodir') if !isdirectory(target_path) "如果位置不存在,则创建目录
call mkdir(target_path, "p", 0700)
endif let &undodir=target_path "变量赋值
set undofile "开启撤销永久化
endif
二、用Makefile编译文件
1.1 C语言程序
创建Makefile文件(vim Makefile)
CC = sw9gcc
FC = sw9gfortran
MPI_C = /usr/sw/mpi/mpi_20210219_SEA/bin/mpicc
EXE = main_dnn
LIB = ./utils/libs/libswdnn_xu.a
OBJDIR = ./obj CFLAGS = -msimd -I./utils/include/ -mieee -g -O3 -funroll-nest-loops -mfma -fipa-type-escape -fipa-struct-peeling -fprefetch-loop-arrays
#CFLAGS += -DDEBUG
LIBFLAGS = -fcache-hint -mhybrid slavesrc = $(wildcard ./utils/slave/*.c)
mastersrc = $(wildcard ./utils/master/*.c)
utilsrc = $(wildcard ./utils/src/*.c)
LIBOBJ1 += $(patsubst %.c, %.o, $(slavesrc) $(mastersrc) $(utilsrc))
LIBOBJ2 = $(notdir $(LIBOBJ1))
OBJ += $(patsubst %.o, $(OBJDIR)/%.o, $(LIBOBJ2)) all: $(EXE)
ar: $(LIB)
$(EXE): $(OBJDIR)/main_dnn.o $(LIB)
$(CC) $(LIBFLAGS) -o $@ $^ -lm -lm_slave -L/usr/sw/yyzlib/xMath-SACA -lswblas
$(LIB): $(OBJ)
sw9ar rcs $@ $^
$(OBJDIR)/main_dnn.o: main_dnn.c
$(CC) -Dcheck_res $(CFLAGS) -mhost -c $^ -o $@
$(OBJDIR)/%.o: ./utils/master/%.c
$(CC) $(CFLAGS) -mhost -c $^ -o $@
$(OBJDIR)/%.o: ./utils/src/%.c
$(CC) $(CFLAGS) -mhost -c $^ -o $@
$(OBJDIR)/%.o: ./utils/slave/%.c
$(CC) $(CFLAGS) -mpws -mslave -Dperf -c $^ -o $@ .PHONY: clean
clean:
rm -f ${LIB} $(EXE) $(OBJDIR)/*.o
~
1.2 Fortran语言程序
创建Makefile文件(vim Makefile)
# 获取文件夹中所有.f90文件列表 notdir把展开的文件去除掉路径信息
SRCS_F90 = $(wildcard *.f90)
SRCS_F = $(wildcard ./*.f)
SRCS_DIR = $(notdir $(SRCS_F))
# 替换.f90后缀为.o后缀 得到.o文件列表 notdir用于去掉文件的绝对路径,只保留文件名
OBJS_F90 = $(patsubst %.f90, %.o, $(SRCS_F90))
OBJS_F = $(patsubst %.f, %.o, $(SRCS_DIR)) # module依赖文件
MOD_OBJS = variable.o mpi_variable.o mod_split_funs.o
MOD_SRCS = variable.f90 mpi_variable.f90 mod_split_funs.f90 # 定义编译器变量
F90= mpif90
FC = mpif90 FFLAGS = -O2 # 定义目标变量
EXE = main all:$(EXE)
# @echo $(SRCS_F)
# @echo $(SRCS_DIR)
# @echo $(OBJS_F) # $^表示所有依赖文件 $@--目标文件,$<第一个依赖文件
$(EXE): $(OBJS_F90) $(OBJS_F)
$(F90) -o $@ $^
# $(FC) -o $(EXE) $(OBJS) # %.o %.f90 %.mod 表示任意文件
%.o: %.f
$(FC) -c $< -o $@
%.o: %.f90 $(MOD_OBJS)
$(F90) $(CFLAGS) -c $< -o $@
$(MOD_OBJS): $(MOD_SRCS)
$(F90) -c $^ # *.o 表示所有.o文件
.PHONY: clean
clean:
rm -f *.o *.mod
~
三、用Cmake编译文件
2.1 C语言程序
1、创建CMakeLists.txt文件(vim CMakeLists.txt)
cmake_minimum_required(VERSION 3.16.2) # 声明使用CMAKE的最低版本要求
project(main_blas LANGUAGES C) # 定义项目的名字 #find_package(MPI REQUIRED) # 寻找 MPI
#include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/include) # 引入头文件目录
# 打印信息
message(WARNING "This application cannot compile without MPI end end ") # 设置编译目标类型是Debug、Release版还是RelWithDebInfo版本
#set(DEFAULT_BUILD_TYPE "RelWithDebInfo")
set(CMAKE_BUILD_TYPE Release) # 设置编译器选项
set(CMAKE_C_FLAGS "-msimd -mieee")
set(CMAKE_C_FLAGS_RELEASE "-O3 ") # Release版编译器选项
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-g -O3")
# 静态库的输出目录
#set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/utils/libs) # 添加工作目录下子目录src中的源文件到SRC变量
file(GLOB SRC ${PROJECT_SOURCE_DIR}/utils/src/*.c)
file(GLOB MASTER_SRC ${PROJECT_SOURCE_DIR}/utils/master/*.c)
file(GLOB SLAVE_SRC ${PROJECT_SOURCE_DIR}/utils/slave/*.c) # 传递编译器选项
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mhost")
set_source_files_properties(${MASTER_SRC} PROPERTIES COMPILE_FLAGS "-mhost")
set_source_files_properties(${SLAVE_SRC} PROPERTIES COMPILE_FLAGS "-mslave -mfma -mpws -Dperf") # 将SRCS编译为swdnn_xu这个静态链接库
add_library(swdnn_xu STATIC ${SRC} ${MASTER_SRC} ${SLAVE_SRC})
target_include_directories(swdnn_xu PRIVATE ${PROJECT_SOURCE_DIR}/utils/include)
set_target_properties(swdnn_xu PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/utils/libs) # 静态库的输出目录 link_directories("${PROJECT_SOURCE_DIR}/utils/libs" "/usr/sw/yyzlib/xMath-SACA/") # 指定静态库路径
# 生成可执行文件 ${CMAKE_PROJECT_NAME}指项目名 main_blas
add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/main_blas.c)
target_link_options(${PROJECT_NAME} PRIVATE "-mhybrid" "-Wl,-zmuldefs")
#set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "-mhybrid -Wl,-zmuldefs") # 指定链接选项
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/utils/include) # 指定头文件路径
target_link_libraries(${PROJECT_NAME} swdnn_xu -lcblas -lswblas -lgfortran -lm -lm_slave) # 指定要链接的静态库
2、执行编译文件(./cm.sh)
#!/bin/sh
set -ex file=build rm -rf ${file} DIR=$(dirname $(readlink -f ${BASH_SOURCE[0]})) # -DCMAKE_TOOLCHAIN_FILE=${DIR}/cmake/toolchain-sw_64.cmake
cmake . -B ${file} \
-DCMAKE_C_COMPILER=/usr/sw/mpi/mpi_20210219_SEA/bin/mpicc \
-DCMAKE_AR=/usr/sw/swgcc/swgcc710-tools-SEA-1307/usr/bin/sw9ar cd ${file}
make -j
3、编译器环境变量设置(不需要)
vim cmake/toolchain-sw_64.cmake
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR sw_64) set(CMAKE_C_COMPILER /usr/sw/mpi/mpi_20210219_SEA/bin/mpicc)
set(CMAKE_CXX_COMPILER /usr/sw/mpi/mpi_20210219_SEA/bin/mpicxx)
set(CMAKE_AR /usr/sw/swgcc/swgcc710-tools-SEA-1208/usr/bin/sw9ar)
set(MPI_C_COMPILER /usr/sw/mpi/mpi_20210219_SEA/bin/mpicc)
set(MPI_CXX_COMPILER /usr/sw/mpi/mpi_20210219_SEA/bin/mpicxx)
set(SW_C_COMPILER /usr/sw/swgcc/swgcc710-tools-SEA-1208/usr/bin/sw9gcc)
set(SW_CXX_COMPILER /usr/sw/swgcc/swgcc710-tools-SEA-1208/usr/bin/sw9g++)
~
2.2 Fortran语言程序
创建CMakeLists.txt文件(vim CMakeLists.txt)
简单版Cmake(FC=mpif90 cmake . -B build -DCMAKE_Fortran_COMPILER=/usr/local/bin/mpif90)
cmake_minimum_required(VERSION 3.21.4) # 声明使用CMAKE的最低版本要求
project(xu_main LANGUAGES Fortran) # 定义项目的名字 find_package(MPI REQUIRED) # 寻找 MPI
#include_directories(SYSTEM ${MPI_INCLUDE_PATH}) # 引入头文件目录 # 设置编译目标类型是release版还是debug版本
set(DEFAULT_BUILD_TYPE "Release") set(CMAKE_Fortran_FLAGS "-O2") # 设置编译器选项 # 添加工作目录下子目录src中的源文件到SRC变量
file(GLOB SRC ./funs9/*.f90 ${PROJECT_SOURCE_DIR}/funs9/*.f) # 生成可执行文件 ${CMAKE_PROJECT_NAME}指项目名 xu_main
add_executable(${CMAKE_PROJECT_NAME} ${SRC} )
2.3 命令简介
2.3.1 project
project命令用于指定cmake工程的名称,实际上,它还可以指定cmake工程的版本号(VERSION关键字)、简短的描述(DESCRIPTION关键字)、主页URL(HOMEPAGE_URL关键字)和编译工程使用的语言(LANGUAGES关键字)。
(1)参数project(<PROJECT_NAME> [VERSION <major>] [DESCRIPTION <project-description-string>] [HOMEPAGE_URL <url-string>] [LANGUAGES <language-name>])
PROJECT_NAME:将当前工程的名称赋值给PROJECT_NAME,同时${PROJECT_NAME}变量赋值为PROJECT_NAME。
VERSION:指定工程的版本号。
DESCRIPTION:对工程的文本描述。
HOMEPAGE_URL:指定工程的主页URL。
LANGUAGES选项:选择构建工程需要的编程语言。
(2)当定义了project()后,一些cmake自带变量会自动赋值
PROJECT_NAME:将当前工程的名称赋值给PROJECT_NAME。
PROJECT_SOURCE_DIR:当前工程的源码路径。
CMAKE_PROJECT_NAME:顶层工程的名称。例如当前调用的CMakeLists.txt位于顶层目录(可以理解为使用cmake命令首次调用的那个CMakeLists.txt),那么工程名还会赋值给CMAKE_PROJECT_NAME。
2.3.2 add_executable生成可执行文件
1、参数add_executable(<name> <EXCLUDE_FROM_ALL> <source1> <source2 ...>)
name:可执行目标文件的名字,在一个cmake工程中,这个名字必须全局唯一。
EXCLUDE_FROM_ALL:用于指定可执行目标是否会被构建,当该选项使用的时候,可执行目标不会被构建。
[source1] [source2 …]:构建可执行目标文件所需要的源文件。
2、EXCLUDE_FROM_ALL参数用法
project(test)
add_executable(test EXCLUDE_FROM_ALL test.f90)
// test加了EXCLUDE_FROM_ALL属性,在默认编译的时候,不会被编译,
// 如果要编译它,需要手动编译,比如make test指定编译名为test
make test
2.3.3 add_library编译出静态库和动态库
1、add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [source1 source2 ...])
STATIC、SHARED 和 MODULE 表示库文件的类型,分别表示静态库、动态库和可加载模块;
# 将SRCS编译为swdnn_xu这个静态链接库
add_library(swdnn_xu STATIC ${SRC} ${MASTER_SRC} ${SLAVE_SRC})
2.3.4 link_libraries 和 target_link_libraries 链接库
1、link_libraries(link_libraries 基本上被遗弃了,尽可能用 target_link_libraries)
link_libraries("/usr/sw/yyzlib/xMath-SACA/libswblas.a")
add_executable(${PROJECT_NAME} main.c)
2、target_link_libraries(<target> <PRIVATE | PUBLIC | INTERFACE> <item>...)
link_directories("/usr/sw/yyzlib/xMath-SACA") # 指定静态库路径
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} swzgemm_xu /usr/sw/yyzlib/xMath-SACA/libswblas.a) target_link_libraries(${PROJECT_NAME} libswzgemm_xu.a) #这些库名写法都可以。
target_link_libraries(${PROJECT_NAME} swzgemm_xu)
target_link_libraries(${PROJECT_NAME} -lswzgemm_xu)
【注】:调用link_directories必须在生成可执行文件之前调用,也就是在add_executable之前调用
target_link_libraries(PUBLIC target target1 target2)
target_link_libraries(PUBLIC target3 target target4)
//PUBLIC:表示target能够使用target1&target2库中内容,target3也能使用target1&target2库中内容;默认状态为PUBLIC。
target_link_libraries(PRIVATE target target1 target2)
target_link_libraries(PRIVATE target3 target target4)
//PRIVATE:表示target能够使用target1&target2库中内容,target3不能使用target1&target2中定义的内容,只能使用target中定义的内容。
target_link_libraries(INTERFACE target target1 target2)
target_link_libraries(INTERFACE target3 target target4)
//INTERFACE:表示target无法使用target1&target2库中内容,但是target3能使用target1&target2中内容。
3、link_libraries 和 target_link_libraries 区别
(1)link_libraries用在add_executable之前,target_link_libraries用在add_executable之后
(2)link_libraries用来链接静态库,target_link_libraries用来链接导入库,即按照header file + .lib + .dll方式隐式调用动态库的.lib库
(3)link_libraries 基本上被遗弃了,尽可能用 target_link_libraries
2.3.5 include_directories 和 target_include_directories引用头文件
1、include_directories([AFTER | BEFORE] [SYSTEM] [<dir1> <dir2> ...])
include_directories(SYSTEM ${PROJECT_SOURCE_DIR}/include) # 引入头文件目录
add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/main_blas.c)
默认情况下,指定的目录被追加到当前目录列表中。这个默认行为可以通过将CMAKE_INCLUDE_DIRECTORIES_BEFORE设置为ON来改变。通过显式使用AFTER或BEFORE,可以在appending和prepending之间进行选择,而不依赖于默认值。
如果给出了SYSTEM选项,编译器将被告知在某些平台上目录是系统包含目录。
2、target_include_directories(<target> [SYSTEM][AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...][<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/main_blas.c)
target_include_directories(${PROJECT_NAME} PRIVATE ${PROJECT_SOURCE_DIR}/utils/include) # 指定头文件路径
3、区别
(1)include_directories:当前CMakeLists.txt的所有目标,以及之后添加的所有子目录的目标添加头文件搜索路径。因此,慎用include_directories,因为会影响全局target。
(2)target_include_directories:指定目标包含的头文件路径。如果想为不同目标设置不同的搜索路径,那么用target_include_directories更合适。
2.3.6 add_subdirectory添加子目录
1、语法:add_subdirectory (source_dir [binary_dir] [EXCLUDE_FROM_ALL])
2、作用:添加一个子目录并构建该子目录,告诉CMAKE我还有其它子目录的CMakeList.txt需要编译。
3、参数
(1)source_dir:必选参数。该参数指定一个子目录,子目录下应该包含CMakeLists.txt文件和代码文件。子目录可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前目录的一个相对路径。
(2)binary_dir:可选参数。该参数指定一个目录,用于存放输出文件。可以是相对路径也可以是绝对路径,如果是相对路径,则是相对当前输出目录的一个相对路径。如果该参数没有指定,则默认的输出目录使用source_dir。
(3)EXCLUDE_FROM_ALL:可选参数。当指定了该参数,则子目录下的目标不会被父目录下的目标文件包含进去,父目录的CMakeLists.txt不会构建子目录的目标文件,必须在子目录下显式去构建。例外情况:当父目录的目标依赖于子目录的目标,则子目录的目标仍然会被构建出来以满足依赖关系(例如使用了target_link_libraries)。
2.3.7 target_compile_options设置目标的编译选项
add_executable(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/main_blas.c)
target_compile_options(${PROJECT_NAME} PRIVATE "-O3")
2.3.8 将目标文件保存到指定目录下
1、设置输出目录
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib) # 动态库
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/static) # 静态库
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin) # 执行文件
2、指向性保存
同样是指定输出目录,但是不同的动态库文件指定不同的输出目录。(静态库和二进制执行文件也是同理)。目标文件可以大致分为三种类型:二进制执行文件、动态库、静态库。保存不同目标文件所用到的属性不一样。具体分类如下。
RUNTIME_OUTPUT_DIRECTORY:二进制执行文件
LIBRARY_OUTPUT_DIRECTORY:动态库
ARCHIVE_OUTPUT_DIRECTORY:静态库
add_library(swdnn_xu STATIC ${SRC} ${MASTER_SRC} ${SLAVE_SRC})
set_target_properties(swdnn_xu PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/utils/libs)
2.3.9 设置目标的链接选项
target_compile_options(${PROJECT_NAME} PRIVATE "-mhybrid -Wl,-zmuldefs")
target_link_options(${PROJECT_NAME} PRIVATE "-mhybrid" "-Wl,-zmuldefs")
aaaa
用【Makefile】或【Cmake】编译【C/Fortran】程序文件的更多相关文章
- Windows下使用mingw+cmake编译C/C++程序
按照正常流程安装好mingw和cmake后,仍然是无法直接使用cmake编译处MakeFile文件的,我们需要在CMakeLists.txt中做一些配置. 首先,在PROJECT之前,设置: SET( ...
- vscode, cmake编译多个C++文件
目的是利用vscode及相关插件编译多个C++文件. 我已经装好cmake和mingw并且将它们的路径添加到系统变量path中了. vscode装上如下几个插件: 点击vscode左上角 文件-& ...
- 在ubunt14.04(linux)下利用cmake编译运行opencv程序
今天在电脑上安装好了opencv环境,迫不及待的想写个程序来测试一下.但是在windows下我们用vs等集成开发工具.可是在linux下我们应该怎么办呢? 这里我们用了opencv推荐的cmake来编 ...
- [转]一个CMake编译问题的解决过程
问题的提出 公司的一个power-pc平台的产品,有个协议进行了修改,过程中出现了比较奇怪的情况.直接将修改后的动态库下载到设备上(原始设备是有文件系统和其他的依赖文件的,相当于部分更新应用),设备和 ...
- Ubuntu系统---编译opencv程序的几种方式g++、Makefile、Cmake
Ubuntu系统---编译opencv程序的几种方式g++.Makefile.Cmake 先建立一个工程(一个文件夹),写好xxx.cpp文件,可以是多个: //----------opencv.cp ...
- Linux 编译工具 gcc/g++、Make/Makefile、CMake/CMakeLists.txt、qmake
前言 编译器的主要工作流程: 源码(Source Code)>> 预处理器(Preprocessor)>> 编译器(Compiler)>> 汇编程序(Assembl ...
- Cmake知识----编写CMakeLists.txt文件编译C/C++程序
1.CMake编译原理 CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多.CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt ...
- linux 下 VSCODE 使用CMake编译STM32程序
项目在做什么 项目地址 本项目是为了研究MCU在linux下开发而做的 --build 存放cmake编译生成的文件 --cmake 存放cmake编译时会用到的文件,比如工具链检查.编译选项等 -- ...
- cmake编译c++程序
当在Linux系统下编写程序时候,如果没有类似于visual studio.vs code等IDE(集成开发环境)时,如何编译.运行程序呢?一种方法是编写makefile文件,用makefile文件管 ...
- Cmake知识----编写CMakeLists.txt文件编译C/C++程序(转)
1.CMake编译原理 CMake是一种跨平台编译工具,比make更为高级,使用起来要方便得多.CMake主要是编写CMakeLists.txt文件,然后用cmake命令将CMakeLists.txt ...
随机推荐
- 帕鲁重大更新!macOS 竟然也能玩了
近日,<幻兽帕鲁>迎来了 v0.2.1.0 大版本的更新. 本次更新的最大亮点是新实装的突袭头目系统.玩家可以在 "召唤祭坛" 献祭石板,从而召唤强大的突袭头目.其中, ...
- .NET Aspire预览5版本 发布
2024年4月11日发布了.NET Aspire预览5版本,这个版本引入了对AWS的支持,并对Azure功能进行了改进.重点内容包括拆分Aspire.Hosting和Aspire.Hosting.Az ...
- sql 语句系列(月份的第一天和最后一天)[八百章之第二十章]
前言 插播一个,从给定日期值里面提取年月日时分秒. 之所以写这个是因为使用频率太高. mysql: select DATE_FORMAT(CURRENT_TIMESTAMP,'%k') hr, DAT ...
- 重新点亮linux 命令树————网络管理和网络配置文件[十一六]
前言 简单整理一下网络管理和网络配置文件. 正文 网络服务程序分为两种:分别是SysV和systemd service network start|stop|restart chkconfig --l ...
- .NET8中的Microsoft.Extensions.Http.Resilience库
接上一篇,https://www.cnblogs.com/vipwan/p/18129361 借助Aspire中新增的Microsoft.Extensions.ServiceDiscovery库,我们 ...
- 深度解读《深度探索C++对象模型》之拷贝构造函数
接下来我将持续更新"深度解读<深度探索C++对象模型>"系列,敬请期待,欢迎关注!也可以关注公众号:iShare爱分享,自动获得推文. 写作不易,请有心人到我的公众号上 ...
- 力扣119(java)-杨辉三角Ⅱ(简单)
题目: 给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行. 在「杨辉三角」中,每个数是它左上方和右上方的数的和. 示例 1: 输入: rowIndex = 3输出: [1 ...
- 牛客网-SQL专项练习2
①从学生信息表(student)中提取姓名(name)列值为NULL的记录,SQL语句为: 解析:注意不是只查name值,而是查name值为空的所有信息 SQL语句为: SELECT * FROM s ...
- 如何将传统 Web 框架迁移部署到 Serverless 架构?
简介: 与其说 Serverless 架构是一个新的概念,不如说它是一种全新的思路,一种新的编程范式. 与其说 Serverless 架构是一个新的概念,不如说它是一种全新的思路,一种新的编程范式. ...
- 基于 K8s 的交付难题退退退!| 独家交付秘籍(第三回)
简介: 经过仔细研究,我们发现秘籍中提到许多帮助解决交付问题的招式,而其中一个让我们印象很深,是关于在原有社区版容器底座 Kubernetes(以下简称 K8s)的基础上,对容器底座进行改进,可更好的 ...