首先,不得不認可,cmake很強大,發展了這麼多年,整個生態已經至關完善,功能也至關豐富,這點xmake目前是比不了的。html
當初我作xmake的目的,也並非爲了徹底替代cmake,這沒啥意義,只是以爲cmake的語法和易用性知足不了我,我仍是更喜歡更簡單直觀的方式去描述和維護項目,在不一樣平臺下提供近乎一致的使用體驗。linux
所以,xmake的語法描述和使用體驗仍是很是好的,這也是xmake最大的亮點之一,我在這塊設計上作了不少改進,爲了下降學習和項目維護門檻,也更容易快速上手。android
在這裏,我只拿xmake中一些比較佔優的特性去跟cmake做對比,僅僅只是爲了突出說明xmake在某些方面的優點和易用性,並無任何貶低cmake的意思。git
若是你們看完此篇文章的對比分析,以爲xmake確實好用,可以知足部分項目維護上的需求,解決一些痛點,提升項目維護效率的話,不妨試試體驗下。github
我先羅列下構建工具的一些主要基礎特性對比,大部分特性二者都是支持的,而xmake的優點主要仍是在:語法、包倉庫管理、構建體驗上macos
feature | xmake | cmake |
---|---|---|
語法 | Lua語法,簡潔直觀,快速上手 | DSL,複雜,學習成本高 |
自建包倉庫管理 | 多倉庫支持,可自建私有包倉庫 | 不支持 |
第三方包管理集成 | vcpkg/conan/brew | vcpkg/conan/其餘 |
構建行爲 | 直接構建,無依賴 | 生成工程文件,調用第三方構建工具 |
依賴 | 僅依賴編譯工具鏈 | 依賴編譯工具鏈+第三方構建工具 |
查找依賴包 | 支持 | 支持 |
編譯器特性檢測 | 支持 | 支持 |
工程文件生成 | 支持 | 支持 |
跨平臺 | 支持 | 支持 |
IDE/編輯器插件 | 支持 | 支持 |
模塊和插件擴展 | 支持 | 支持 |
target("test")
set_kind("binary")
add_files("src/main.c")
複製代碼
add_executable(test "")
target_sources(test PRIVATE src/main.c)
複製代碼
xmake支持通配符匹配的方式,添加一批源文件進來,*.c
匹配當前目錄下全部文件,**.c
匹配遞歸目錄下全部文件。windows
這種方式,對於日常項目中新增一些文件編譯,就不須要每次修改xmake.lua了,自動同步,能夠節省很多時間。架構
target("test")
set_kind("binary")
add_files("src/*.c")
add_files("test/*.c", "example/**.cpp")
複製代碼
xmake的add_files()
是很是靈活強大的,不只能夠支持各類不一樣類型源文件添加,還能夠在添加的同時排除一些指定文件。iphone
好比:遞歸添加src下的全部c文件,可是不包括src/impl/下的全部c文件。編輯器
add_files("src/**.c|impl/*.c")
複製代碼
更多關於這個接口的使用說明,見相關文檔:add_files接口文檔
cmake彷佛須要先遍歷文件列表到對應變量,再添加到對應的target中去才行,稍微繁瑣些。
add_executable(test "")
file(GLOB SRC_FILES "src/*.c")
file(GLOB TEST_FILES "test/*.c")
file(GLOB_RECURSE EXAMPLE_FILES "example/*.cpp")
target_sources(test PRIVATE
${SRC_FILES}
${TEST_FILES}
${EXAMPLE_FILES}
)
複製代碼
target("test")
set_kind("binary")
add_files("src/main.c")
if is_plat("macosx", "linux") then
add_defines("TEST1", "TEST2")
end
if is_plat("windows") and is_mode("release") then
add_cxflags("-Ox", "-fp:fast")
end
複製代碼
add_executable(test "")
if (APPLE OR LINUX)
target_compile_definitions(test PRIVATE TEST1 TEST2)
endif()
if (WIN32)
target_compile_options(test PRIVATE $<$<CONFIG:Release>:-Ox -fp:fast>)
endif()
target_sources(test PRIVATE
src/main.c
)
複製代碼
xmake能夠在編譯構建的不一樣階段(包括編譯、安裝、打包、運行),方便的插入一段自定義腳原本處理本身的邏輯,好比編譯完成以後打印一行輸出:
target("test")
set_kind("binary")
add_files("src/*.c")
after_build(function (target)
print("target file: %s", target:targetfile())
end)
複製代碼
或者自定義運行和安裝邏輯:
target("test")
set_kind("binary")
add_files("src/*.c")
on_install(function (target)
os.cp(target:targetfile(), "/usr/local/bin")
end)
on_run(function (target)
os.run("%s --help", target:targetfile())
end)
複製代碼
在自定義腳本中,用戶能夠寫各類複雜腳本,經過import接口,能夠導入各類擴展模塊來使用。
target("test")
set_kind("binary")
add_files("src/*.c")
before_build(function (target)
import("net.http")
import("devel.git")
http.download("https://xmake.io", "/tmp/index.html")
git.clone("git@github.com:tboox/xmake.git", {depth = 1, branch = "master", outputdir = "/tmp/xmake"})
end)
複製代碼
cmake也能夠經過add_custom_command
來實現:
add_executable(test "")
target_sources(test PRIVATE src/main.c)
add_custom_command(TARGET test POST_BUILD
COMMENT "hello cmake!"
)
複製代碼
不過看了下,不一樣階段,自定義腳本的方式並不徹底同樣,add_custom_command
只能用於構建階段的自定義,若是要對安裝階段進行自定義,得:
install(SCRIPT cmake_install.cmake)
複製代碼
而且只能整個替換安裝邏輯,沒法對安裝先後的實現一些自定義邏輯,另外像打包、運行等其餘階段的自定義彷佛不支持。
一般狀況,編譯默認平臺執行敲xmake,執行構建期間,xmake不會依賴其餘第三方構建工具,連make也不依賴,也不會生成IDE/Makefile文件, 而是直接調用的編譯工具鏈進行編譯,默認會根據cpu核數自動開啓多任務加速構建。
xmake
複製代碼
而cmake的一般是先生成對應IDE/Makefile等第三方構建文件,而後調用make/msbuild等第三方構建工具去編譯。
cmake .
cmake --build .
複製代碼
xmake能夠以近乎一致的方式快速切換不一樣平臺和架構來編譯。
xmake f -p [iphoneos|android|linux|windows|mingw] -a [arm64|armv7|i386|x86_64]
xmake
複製代碼
cmake彷佛對不一樣平臺和架構的編譯配置方式,差別性仍是有些的,須要花點時間研究下才行。
cmake -G Xcode -DIOS_ARCH="arm64" .
cmake --build .
複製代碼
cmake -G "Visual Studio 9 2008" -A x64
cmake --build .
複製代碼
像android平臺編譯,配置ndk的方式彷佛也很繁瑣。
cmake .. -DCMAKE_TOOLCHAIN_FILE=%ANDROID_NDK%\build\cmake\android.toolchain.cmake -DCMAKE_SYSTEM_NAME="Android" -DANDROID_NDK=%ANDROID_NDK% -DANDROID_TOOLCHAIN=clang -DANDROID_PLATFORM=android-24
複製代碼
xmake install
複製代碼
cmake -P cmake_install.cmake
複製代碼
大部分狀況下,xmake不須要寫自定義腳本就能夠直接加載運行編譯生成的目標程序。
xmake run
複製代碼
cmake我沒找到能夠快速運行指定目標程序的方式,可是應該能夠經過寫一個自定義腳本去加載運行它。
cmake -P cmake_run.cmake
複製代碼
xmake也是支持跟cmake的find_package
相似的接口去直接查找系統庫,而後集成使用,找到庫後,會自動追加includedirs, links, linkdirs等相關設置。
target("test")
set_kind("binary")
add_files("src/*.c")
on_load(function (target)
target:add(find_packages("openssl", "zlib"))
end)
複製代碼
add_executable(test main.c)
find_package(OpenSSL REQUIRED)
if (OpenSSL_FOUND)
target_include_directories(test ${OpenSSL_INCLUDE_DIRS})
target_link_libraries(test ${OpenSSL_LIBRARIES})
endif()
find_package(Zlib REQUIRED)
if (Zlib_FOUND)
target_include_directories(test ${Zlib_INCLUDE_DIRS})
target_link_libraries(test ${Zlib_LIBRARIES})
endif()
複製代碼
xmake會自動調用conan工具去下載安裝openssl庫,而後集成使用,只須要執行xmake命令便可完成編譯。
add_requires("conan::OpenSSL/1.0.2n@conan/stable", {alias = "openssl"})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("openssl")
複製代碼
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.14/conan.cmake"
"${CMAKE_BINARY_DIR}/conan.cmake")
endif()
include(${CMAKE_BINARY_DIR}/conan.cmake)
conan_cmake_run(REQUIRES OpenSSL/1.0.2n@conan/stable
BASIC_SETUP
BUILD missing)
add_executable(test main.c)
target_link_libraries(main ${CONAN_LIBS})
複製代碼
xmake有自建的包倉庫,雖然如今裏面包還不是不少,但後期會不斷完善:xmake-repo
咱們只須要添加相關須要的包就好了,很是方便,而且支持多版本選擇和語義版本控制哦。
甚至有些經常使用包支持多平臺集成使用,例如:zlib庫等,即便編譯android/iphoneos/mingw等平臺,也均可以直接下載安裝使用。
add_requires("libuv master", "ffmpeg", "zlib 1.20.*")
add_requires("tbox >1.6.1", {optional = true, debug = true})
target("test")
set_kind("shared")
add_files("src/*.c")
add_packages("libuv", "ffmpeg", "tbox", "zlib")
複製代碼
執行xmake命令後,會去自動從倉庫中下載對應的包而後編譯安裝,集成連接進來,效果以下:
除了官方的包倉庫,用戶也能夠本身建立多個私有倉庫,用來集成使用一些私有包,這對於公司內部項目的依賴維護仍是頗有幫助的。
咱們只須要在xmake.lua加上本身的私有倉庫地址就好了:
add_repositories("my-repo git@github.com:myrepo/xmake-repo.git")
複製代碼
或者直接命令行添加:
xmake repo --add my-repo git@github.com:myrepo/xmake-repo.git
複製代碼
關於這塊的詳細說明能夠看下相關文檔:
最後,附帶一張xmake的依賴包管理架構圖:
這塊我沒看到cmake有支持,不過cmake我用得並很少,若是有寫的不對的地方,你們能夠指正。