xmake v2.5.9 发布,改进 C++20 模块, 支持 Nim, Unity Build
xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更加简洁直观,对新手非常友好,短时间内就能快速入门,能够让用户把更多的精力集中在实际的项目开发上。
这个版本,我们增加了大量重量级的新特性,例如:Nim 语言项目的构建支持,Keil MDK,Circle 和 Wasi 工具链支持。
另外,我们对 C++20 Modules 进行了大改进,不仅支持最新 gcc-11, clang 和 msvc 编译器,而且还得模块间依赖做了自动分析,实现最大程度的并行化编译支持。
最后,还有一个比较有用的特性就是 Unity Build 支持,通过它我们可以对 C++ 代码的编译速度做到很大程度的提升。
新特性介绍
Nimlang 项目构建
最近,我们新增了对 Nimlang 项目的构建支持,相关 issues 见:#1756
创建空工程
我们可以使用 xmake create
命令创建空工程。
xmake create -l nim -t console test xmake create -l nim -t static test xmake create -l nim -t shared test
控制台程序
add_rules("mode.debug", "mode.release") target("test") set_kind("binary") add_files("src/main.nim")
$ xmake -v [ 33%]: linking.release test /usr/local/bin/nim c --opt:speed --nimcache:build/.gens/test/macosx/x86_64/release/nimcache -o:b uild/macosx/x86_64/release/test src/main.nim [100%]: build ok!
静态库程序
add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/foo.nim") target("test") set_kind("binary") add_deps("foo") add_files("src/main.nim")
$ xmake -v [ 33%]: linking.release libfoo.a /usr/local/bin/nim c --opt:speed --nimcache:build/.gens/foo/macosx/x86_64/release/nimcache --app :staticlib --noMain --passC:-DNimMain=NimMain_B6D5BD02 --passC:-DNimMainInner=NimMainInner_B6D5B D02 --passC:-DNimMainModule=NimMainModule_B6D5BD02 --passC:-DPreMain=PreMain_B6D5BD02 --passC:-D PreMainInner=PreMainInner_B6D5BD02 -o:build/macosx/x86_64/release/libfoo.a src/foo.nim [ 66%]: linking.release test /usr/local/bin/nim c --opt:speed --nimcache:build/.gens/test/macosx/x86_64/release/nimcache --pa ssL:-Lbuild/macosx/x86_64/release --passL:-lfoo -o:build/macosx/x86_64/release/test src/main.nim [100%]: build ok!
动态库程序
add_rules("mode.debug", "mode.release") target("foo") set_kind("shared") add_files("src/foo.nim") target("test") set_kind("binary") add_deps("foo") add_files("src/main.nim")
$ xmake -rv [ 33%]: linking.release libfoo.dylib /usr/local/bin/nim c --opt:speed --nimcache:build/.gens/foo/macosx/x86_64/release/nimcache --app :lib --noMain -o:build/macosx/x86_64/release/libfoo.dylib src/foo.nim [ 66%]: linking.release test /usr/local/bin/nim c --opt:speed --nimcache:build/.gens/test/macosx/x86_64/release/nimcache --pa ssL:-Lbuild/macosx/x86_64/release --passL:-lfoo -o:build/macosx/x86_64/release/test src/main.nim [100%]: build ok!
C 代码混合编译
add_rules("mode.debug", "mode.release") target("foo") set_kind("static") add_files("src/*.c") target("test") set_kind("binary") add_deps("foo") add_files("src/main.nim")
Nimble 依赖包集成
完整例子见:Nimble Package Example
add_rules("mode.debug", "mode.release") add_requires("nimble::zip >0.3") target("test") set_kind("binary") add_files("src/main.nim") add_packages("nimble::zip")
main.nim
import zip/zlib echo zlibVersion()
Native 依赖包集成
完整例子见:Native Package Example
add_rules("mode.debug", "mode.release") add_requires("zlib") target("test") set_kind("binary") add_files("src/main.nim") add_packages("zlib")
main.nim
proc zlibVersion(): cstring {.cdecl, importc} echo zlibVersion()
Unity Build 加速
我们知道,C++ 代码编译速度通常很慢,因为每个代码文件都需要解析引入的头文件。
而通过 Unity Build,我们通过将多个 cpp 文件组合成一个来加速项目的编译,其主要好处是减少了解析和编译包含在多个源文件中的头文件内容的重复工作,头文件的内容通常占预处理后源文件中的大部分代码。
Unity 构建还通过减少编译链创建和处理的目标文件的数量来减轻由于拥有大量小源文件而导致的开销,并允许跨形成统一构建任务的文件进行过程间分析和优化(类似于效果链接时优化)。
它可以极大提升 C/C++ 代码的编译速度,通常会有 30% 的速度提升,不过根据项目的复杂程度不同,其带来的效益还是要根据自身项目情况而定。
xmake 在 v2.5.9 版本中,也已经支持了这种构建模式。相关 issues 见 #1019。
如何启用?
我们提供了两个内置规则,分别处理对 C 和 C++ 代码的 Unity Build。
add_rules("c.unity_build") add_rules("c++.unity_build")
Batch 模式
默认情况下,只要设置上述规则,就会启用 Batch 模式的 Unity Build,也就是 xmake 自动根据项目代码文件,自动组织合并。
target("test") set_kind("binary") add_includedirs("src") add_rules("c++.unity_build", {batchsize = 2}) add_files("src/*.c", "src/*.cpp")
我们可以额外通过设置 {batchsize = 2}
参数到规则,来指定每个合并 Batch 的大小数量,这里也就是每两个 C++ 文件自动合并编译。
编译效果大概如下:
$ xmake -r [ 11%]: ccache compiling.release build/.gens/test/unity_build/unity_642A245F.cpp [ 11%]: ccache compiling.release build/.gens/test/unity_build/unity_bar.cpp [ 11%]: ccache compiling.release build/.gens/test/unity_build/unity_73161A20.cpp [ 11%]: ccache compiling.release build/.gens/test/unity_build/unity_F905F036.cpp [ 11%]: ccache compiling.release build/.gens/test/unity_build/unity_foo.cpp [ 11%]: ccache compiling.release build/.gens/test/unity_build/main.c [ 77%]: linking.release test [100%]: build ok
由于我们仅仅启用了 C++ 的 Unity Build,所以 C 代码还是正常挨个编译。另外在 Unity Build 模式下,我们还是可以做到尽可能的并行编译加速,互不冲突。
如果没有设置 batchsize
参数,那么默认会吧所有文件合并到一个文件中进行编译。
Group 模式
如果上面的 Batch 模式自动合并效果不理想,我们也可以使用自定义分组,来手动配置哪些文件合并到一起参与编译,这使得用户更加地灵活可控。
target("test") set_kind("binary") add_rules("c++.unity_build", {batchsize = 0}) -- disable batch mode add_files("src/*.c", "src/*.cpp") add_files("src/foo/*.c", {unity_group = "foo"}) add_files("src/bar/*.c", {unity_group = "bar"})
我们使用 {unity_group = "foo"}
来指定每个分组的名字,以及包含了哪些文件,每个分组的文件都会单独被合并到一个代码文件中去。
另外,batchsize = 0
也强行禁用了 Batch 模式,也就是说,没有设置 unity_group 分组的代码文件,我们还是会单独编译它们,也不会自动开启自动合并。
Batch 和 Group 混合模式
我们只要把上面的 batchsize = 0
改成非 0 值,就可以让分组模式下,剩余的代码文件继续开启 Batch 模式自动合并编译。
target("test") set_kind("binary") add_includedirs("src") add_rules("c++.unity_build", {batchsize = 2}) add_files("src/*.c", "src/*.cpp") add_files("src/foo/*.c", {unity_group = "foo"}) add_files("src/bar/*.c", {unity_group = "bar"})
忽略指定文件
如果是 Batch 模式下,由于是自动合并操作,所以默认会对所有文件执行合并,但如果有些代码文件我们不想让它参与合并,那么我们也可以通过 {unity_ignored = true}
去忽略它们。
target("test") set_kind("binary") add_includedirs("src") add_rules("c++.unity_build", {batchsize = 2}) add_files("src/*.c", "src/*.cpp") add_files("src/test/*.c", {unity_ignored = true}) -- ignore these files
Unique ID
尽管 Unity Build 带啦的收益不错,但是我们还是会遇到一些意外的情况,比如我们的两个代码文件里面,全局命名空间下,都存在相同名字的全局变量和函数。
那么,合并编译就会带来编译冲突问题,编译器通常会报全局变量重定义错误。
为了解决这个问题,我们需要用户代码上做一些修改,然后配合构建工具来解决。
比如,我们的 foo.cpp 和 bar.cpp 都有全局变量 i。
foo.cpp
namespace { int i = 42; } int foo() { return i; }
bar.cpp
namespace { int i = 42; } int bar() { return i; }
那么,我们合并编译就会冲突,我们可以引入一个 Unique ID 来隔离全局的匿名空间。
foo.cpp
namespace MY_UNITY_ID { int i = 42; } int foo() { return MY_UNITY_ID::i; }
bar.cpp
namespace MY_UNITY_ID { int i = 42; } int bar() { return MY_UNITY_ID::i; }
接下来,我们还需要保证代码合并后, MY_UNITY_ID
在 foo 和 bar 中的定义完全不同,可以按文件名算一个唯一 ID 值出来,互不冲突,也就是实现下面的合并效果:
#define MY_UNITY_ID <hash(foo.cpp)> #include "foo.c" #undef MY_UNITY_ID #define MY_UNITY_ID <hash(bar.cpp)> #include "bar.c" #undef MY_UNITY_ID
这看上去似乎很麻烦,但是用户不需要关心这些,xmake 会在合并时候自动处理它们,用户只需要指定这个 Unique ID 的名字就行了,例如下面这样:
target("test") set_kind("binary") add_includedirs("src") add_rules("c++.unity_build", {batchsize = 2, uniqueid = "MY_UNITY_ID"}) add_files("src/*.c", "src/*.cpp")
处理全局变量,还有全局的重名宏定义,函数什么的,都可以采用这种方式来避免冲突。
C++20 Modules
xmake 采用 .mpp
作为默认的模块扩展名,但是也同时支持 .ixx
, .cppm
, .mxx
等扩展名。
早期,xmake 试验性支持过 C++ Modules TS,但是那个时候,gcc 还不能很好的支持,并且模块间的依赖也不支持。
最近,我们对 xmake 做了大量改进,已经完整支持 gcc-11/clang/msvc 的 C++20 Modules 构建支持,并且能够自动分析模块间的依赖关系,实现最大化并行编译。
同时,对新版本的 clang/msvc 也做了更好地处理。
set_languages("c++20") target("test") set_kind("binary") add_files("src/*.cpp", "src/*.mpp")
更多例子见:C++ Modules
Lua5.4 运行时支持
上个版本,我们增加了对 Lua5.3 运行时支持,而在这个版本中,我们进一步升级 Lua 运行时到 5.4,相比 5.3,运行性能和内存利用率上都有很大的提升。
不过,目前 xmake 的默认运行时还是 luajit,预计 2.6.1 版本(也就是下个版本),会正式切到 Lua5.4 作为默认的运行时。
尽管切换了 Lua 运行时,但是对于用户端,完全是无感知的,并且完全兼容现有工程配置,因为 xmake 原本就对暴露的 api 提供了一层封装, 对于 lua 版本之间存在兼容性问题的接口,例如 setfenv, ffi 等都隐藏在内部,原本就没有暴露给用户使用。
Keil MDK 工具链支持
我们在这个版本中,还新增了 Keil/MDK 嵌入式编译工具链的支持,相关例子工程:Example
xmake 会自动探测 Keil/MDK 安装的编译器,相关 issues #1753。
使用 armcc 编译
$ xmake f -p cross -a cortex-m3 --toolchain=armcc -c $ xmake
使用 armclang 编译
$ xmake f -p cross -a cortex-m3 --toolchain=armclang -c $ xmake
控制台程序
target("hello") add_deps("foo") add_rules("mdk.console") add_files("src/*.c", "src/*.s") add_defines("__EVAL", "__MICROLIB") add_includedirs("src/lib/cmsis")
静态库程序
add_rules("mode.debug", "mode.release") target("foo") add_rules("mdk.static") add_files("src/foo/*.c")
Wasi 工具链支持
之前我们支持了 wasm 平台的 emcc 工具链来构建 wasm 程序,而这里,我们新加了另外一个启用了 WASI 的 Wasm 工具链来替换 emcc。
$ xmake f -p wasm --toolchain=wasi $ xmake
Circle 工具链支持
我们还新增了 circle 编译器的支持,这是个新的 C++20 编译器,额外附带了一些有趣的编译期元编程特性,有兴趣的同学可以到官网查看:https://www.circle-lang.org/
$ xmake f --toolchain=circle $ xmake
gcc-8/9/10/11 特定版本支持
如果用户额外安装了 gcc-11, gcc-10 等特定版本的 gcc 工具链,在本地的 gcc 程序命名可能是 /usr/bin/gcc-11
。
一种办法是通过 xmake f --cc=gcc-11 --cxx=gcc-11 --ld=g++-11
挨个指定配置来切换,但非常繁琐。
所以,xmake 也提供了更加快捷的切换方式:
$ xmake f --toolchain=gcc-11 -c $ xmake
只需要指定 gcc-11
对应的版本名,就可以快速切换整个 gcc 工具链。
C++17/20 编译器特性检测
xmake 提供了 check_features 辅助接口来检测编译器特性。
includes("check_features.lua") target("test") set_kind("binary") add_files("*.c") add_configfiles("config.h.in") configvar_check_features("HAS_CONSTEXPR", "cxx_constexpr") configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})
${define HAS_CONSTEXPR} ${define HAS_CONSEXPR_AND_STATIC_ASSERT}
config.h
/* #undef HAS_CONSTEXPR */ #define HAS_CONSEXPR_AND_STATIC_ASSERT 1
而在 2.5.9 版本中,我们新增了 c++17 特性检测:
特性名 |
---|
cxx_aggregate_bases |
cxx_aligned_new |
cxx_capture_star_this |
cxx_constexpr |
cxx_deduction_guides |
cxx_enumerator_attributes |
cxx_fold_expressions |
cxx_guaranteed_copy_elision |
cxx_hex_float |
cxx_if_constexpr |
cxx_inheriting_constructors |
cxx_inline_variables |
cxx_namespace_attributes |
cxx_noexcept_function_type |
cxx_nontype_template_args |
cxx_nontype_template_parameter_auto |
cxx_range_based_for |
cxx_static_assert |
cxx_structured_bindings |
cxx_template_template_args |
cxx_variadic_using |
还新增了 c++20 特性检测:
特性名 |
---|
cxx_aggregate_paren_init |
cxx_char8_t |
cxx_concepts |
cxx_conditional_explicit |
cxx_consteval |
cxx_constexpr |
cxx_constexpr_dynamic_alloc |
cxx_constexpr_in_decltype |
cxx_constinit |
cxx_deduction_guides |
cxx_designated_initializers |
cxx_generic_lambdas |
cxx_impl_coroutine |
cxx_impl_destroying_delete |
cxx_impl_three_way_comparison |
cxx_init_captures |
cxx_modules |
cxx_nontype_template_args |
cxx_using_enum |
Xrepo 包虚拟环境管理
进入虚拟环境
xmake 自带的 xrepo 包管理工具,现在已经可以很好的支持包虚拟机环境管理,类似 nixos 的 nixpkgs。
我们可以通过在当前目录下,添加 xmake.lua 文件,定制化一些包配置,然后进入特定的包虚拟环境。
add_requires("zlib 1.2.11") add_requires("python 3.x", "luajit")
$ xrepo env shell > python --version > luajit --version
我们也可以在 xmake.lua 配置加载对应的工具链环境,比如加载 vs 的编译环境。
set_toolchains("msvc")
管理虚拟环境
我们可以使用下面的命令,把指定的虚拟环境配置全局注册到系统中,方便快速切换。
$ xrepo env --add /tmp/base.lua
这个时候,我们就保存了一个名叫 base 的全局虚拟环境,我们可以通过 list 命令去查看它。
$ xrepo env --list /Users/ruki/.xmake/envs: - base envs(1) found!
我们也可以删除它。
$ xrepo env --remove base
切换全局虚拟环境
如果我们注册了多个虚拟环境,我们也可以快速切换它们。
$ xrepo env -b base shell > python --version
或者直接加载指定虚拟环境运行特定命令
$ xrepo env -b base python --version
xrepo env -b/--bind
就是绑定指定的虚拟环境,更多详情见:#1762
Header Only 目标类型
对于 target,我们新增了 headeronly
目标类型,这个类型的目标程序,我们不会实际编译它们,因为它没有源文件需要被编译。
但是它包含了头文件列表,这通常用于 headeronly 库项目的安装,IDE 工程的文件列表生成,以及安装阶段的 cmake/pkgconfig 导入文件的生成。
例如:
add_rules("mode.release", "mode.debug") target("foo") set_kind("headeronly") add_headerfiles("src/foo.h") add_rules("utils.install.cmake_importfiles") add_rules("utils.install.pkgconfig_importfiles")
更多详情见:#1747
从 CMake 中查找包
现在 cmake 已经是事实上的标准,所以 CMake 提供的 find_package 已经可以查找大量的库和模块,我们完全复用 cmake 的这部分生态来扩充 xmake 对包的集成。
我们可以通过 find_package("cmake::xxx")
去借助 cmake 来找一些包,xmake 会自动生成一个 cmake 脚本来调用 cmake 的 find_package 去查找一些包,获取里面包信息。
例如:
$ xmake l find_package cmake::ZLIB { links = { "z" }, includedirs = { "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10. 15.sdk/usr/include" }, linkdirs = { "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10. 15.sdk/usr/lib" } } $ xmake l find_package cmake::LibXml2 { links = { "xml2" }, includedirs = { "/Library/Developer/CommandLineTools/SDKs/MacOSX10.15.sdk/usr/include/libxml2" }, linkdirs = { "/usr/lib" } }
指定版本
find_package("cmake::OpenCV", {required_version = "4.1.1"})
指定组件
find_package("cmake::Boost", {components = {"regex", "system"}})
预设开关
find_package("cmake::Boost", {components = {"regex", "system"}, presets = {Boost_USE_STATIC_LIB = true}}) set(Boost_USE_STATIC_LIB ON) -- will be used in FindBoost.cmake find_package(Boost REQUIRED COMPONENTS regex system)
设置环境变量
find_package("cmake::OpenCV", {envs = {CMAKE_PREFIX_PATH = "xxx"}})
指定自定义 FindFoo.cmake 模块脚本目录
mydir/cmake_modules/FindFoo.cmake
find_package("cmake::Foo", {moduledirs = "mydir/cmake_modules"})
包依赖集成
package("xxx") on_fetch(function (package, opt) return package:find_package("cmake::xxx", opt) end) package_end() add_requires("xxx")
包依赖集成(可选组件)
package("boost") add_configs("regex", { description = "Enable regex.", default = false, type = "boolean"}) on_fetch(function (package, opt) opt.components = {} if package:config("regex") then table.insert(opt.components, "regex") end return package:find_package("cmake::Boost", opt) end) package_end() add_requires("boost", {configs = {regex = true}})
相关 issues: #1632
添加自定义命令到 CMakelists.txt
我们进一步改进了 cmake 生成器,现在可以将 rule 里面自定义的脚本序列化成命令列表,一起生成到 CMakelists.txt
不过目前只能支持 batchcmds 系列脚本的序列化。
rule("foo") after_buildcmd(function (target, batchcmds, opt) batchcmds:show("hello xmake!") batchcmds:cp("xmake.lua", "/tmp/") -- batchcmds:execv("echo", {"hello", "world!"}) -- batchcmds:runv("echo", {"hello", "world!"}) end) target("test") set_kind("binary") add_rules("foo") add_files("src/*.c")
它将会生成类似如下的 CMakelists.txt
# ... add_custom_command(TARGET test POST_BUILD COMMAND echo hello xmake! VERBATIM ) add_custom_command(TARGET test POST_BUILD COMMAND cp xmake.lua /tmp/ VERBATIM ) target_sources(test PRIVATE src/main.c )
不过 cmake 的 ADD_CUSTOM_COMMAND
PRE_BUILD 实际效果在不同生成器上,差异比较大,无法满足我们的需求,因此我们做了很多处理来支持它。
相关 issues: #1735
改进对 NixOS 的安装支持
我们还改进了 get.sh 安装脚本,来更好地支持 nixOS。
更新内容
新特性
- #1736: 支持 wasi-sdk 工具链
- 支持 Lua 5.4 运行时
- 添加 gcc-8, gcc-9, gcc-10, gcc-11 工具链
- #1623: 支持 find_package 从 cmake 查找包
- #1747: 添加
set_kind("headeronly")
更好的处理 headeronly 库的安装 - #1019: 支持 Unity build
- #1438: 增加
xmake l cli.amalgamate
命令支持代码合并 - #1765: 支持 nim 语言
- #1762: 为
xrepo env
管理和切换指定的环境配置 - #1767: 支持 Circle 编译器
- #1753: 支持 Keil/MDK 的 armcc/armclang 工具链
- #1774: 添加 table.contains api
- #1735: 添加自定义命令到 cmake 生成器
- #1781: 改进 get.sh 安装脚本支持 nixos
改进

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
smart-http v1.1.9 发布,一款开源 http 服务器
smart-http 是一款采用 smart-socket 研发的可编程式 http 应用微内核,用户可以在此基础上很轻松的开展 Http 或者 WebSocket 相关的服务端/客户端程序开发。 smart-http 自发布以来获得了很多用户的青睐,通过长期紧密的互动交流,促使该项目从易用性、稳定性和运行性能等方面都得到了显著的进步。 本次发布的两项新特性:Gzip压缩传输和异步响应式服务,皆来自用户的实际需求,我也在第一时间连夜爆肝予以支持。 Gzip压缩传输 通过启用压缩技术可以大大减少网络传输的数据量,提高网页的加载、渲染速度。当然,启用压缩模式会增加些许服务器的性能开销,如果是静态文件可以采用缓存技术消除该影响。 为了检验压缩传输的效果,我们针对同一份文件分别启用压缩模式和非压缩模式的执行http请求(见下图)。可以看到在没有进行的压缩的时候,传输的字节数高达 8541 个字节,而启用压缩后则骤降至 1557 字节,这样的压缩比还是非常可观的。 异步响应式 因为 smart-http 使用的是 AIO 模型,无需额外的 IO 线程组,所以一般推荐直接在 smart-http ...
- 下一篇
smart-doc 2.2.9 发布,Java 零注解 API 文档生成工具
smart-doc 是一款同时支持 java restful api 和 Apache Dubbo rpc 接口文档生成的工具,smart-doc 颠覆了传统类似 swagger 这种大量采用注解侵入来生成文档的实现方法。 smart-doc 完全基于接口源码分析来生成接口文档,完全做到零注解侵入,你只需要按照 java 标准注释编写,smart-doc 就能帮你生成一个简易明了的 markdown 或是一个像 GitBook 样式的静态 html 文档。如果你已经厌倦了 swagger 等文档工具的无数注解和强侵入污染,那请拥抱 smart-doc 吧! 功能特性 支持接口 debug。 零注解、零学习成本、只需要写标准 java 注释。 基于源代码接口定义自动推导,强大的返回结构推导。 支持 Spring MVC,Spring Boot,Spring Boot Web Flux(controller 书写方式)。 支持 Callable,Future,CompletableFuture 等异步接口返回的推导。 支持 JavaBean 上的 JSR303 参数校验规范,支持分组验证。...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- 2048小游戏-低调大师作品
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- CentOS7设置SWAP分区,小内存服务器的救世主
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池