首先,不得不承認,cmake很強大,發展了這麼多年,整個生态已經相當完善,功能也相當豐富,這點xmake目前是比不了的。
當初我做xmake的目的,也并不是為了完全替代cmake,這沒啥意義,隻是覺得cmake的文法和易用性滿足不了我,我還是更喜歡更簡單直覺的方式去描述和維護項目,在不同平台下提供近乎一緻的使用體驗。
是以,xmake的文法描述和使用體驗還是非常好的,這也是xmake最大的亮點之一,我在這塊設計上做了很多改進,為了降低學習和項目維護門檻,也更容易快速上手。
在這裡,我隻拿xmake中一些比較占優的特性去跟cmake作對比,僅僅隻是為了突出說明xmake在某些方面的優勢和易用性,并沒有任何貶低cmake的意思。
如果大家看完此篇文章的對比分析,覺得xmake确實好用,能夠滿足部分項目維護上的需求,解決一些痛點,提高項目維護效率的話,不妨試試體驗下。
- 項目源碼
- 官方文檔
- xmake v2.2.6 釋出, Qt/Android編譯支援
特性支援
我先羅列下建構工具的一些主要基礎特性對比,大部分特性兩者都是支援的,而xmake的優勢主要還是在:文法、包倉庫管理、建構體驗上
文法對比
空工程
xmake
target("test")
set_kind("binary")
add_files("src/main.c")
cmake
add_executable(test "")
target_sources(test PRIVATE src/main.c)
源檔案添加
xmake
xmake支援通配符比對的方式,添加一批源檔案進來,
*.c
比對目前目錄下所有檔案,
**.c
比對遞歸目錄下所有檔案。
這種方式,對于平常項目中新增一些檔案編譯,就不需要每次修改xmake.lua了,自動同步,可以節省不少時間。
target("test")
set_kind("binary")
add_files("src/*.c")
add_files("test/*.c", "example/**.cpp")
xmake的
add_files()
是非常靈活強大的,不僅可以支援各種不同類型源檔案添加,還可以在添加的同時排除一些指定檔案。
比如:遞歸添加src下的所有c檔案,但是不包括src/impl/下的所有c檔案。
add_files("src/**.c|impl/*.c")
更多關于這個接口的使用說明,見相關文檔:add_files接口文檔
cmake
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}
)
條件編譯
xmake
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
cmake
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
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("[email protected]:tboox/xmake.git", {depth = 1, branch = "master", outputdir = "/tmp/xmake"})
end)
cmake
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,執行建構期間,xmake不會依賴其他第三方建構工具,連make也不依賴,也不會生成IDE/Makefile檔案, 而是直接調用的編譯工具鍊進行編譯,預設會根據cpu核數自動開啟多任務加速建構。
xmake
cmake
而cmake的通常是先生成對應IDE/Makefile等第三方建構檔案,然後調用make/msbuild等第三方建構工具去編譯。
cmake .
cmake --build .
編譯指定平台
xmake
xmake可以以近乎一緻的方式快速切換不同平台和架構來編譯。
xmake f -p [iphoneos|android|linux|windows|mingw] -a [arm64|armv7|i386|x86_64]
xmake
cmake
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%buildcmakeandroid.toolchain.cmake -DCMAKE_SYSTEM_NAME="Android" -DANDROID_NDK=%ANDROID_NDK% -DANDROID_TOOLCHAIN=clang -DANDROID_PLATFORM=android-24
安裝目标
xmake
xmake install
cmake
cmake -P cmake_install.cmake
運作目标
xmake
大部分情況下,xmake不需要寫自定義腳本就可以直接加載運作編譯生成的目标程式。
xmake run
cmake
cmake我沒找到可以快速運作指定目标程式的方式,但是應該可以通過寫一個自定義腳本去加載運作它。
cmake -P cmake_run.cmake
依賴支援
查找依賴庫
xmake
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)
cmake
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()
使用第三方庫(Conan)
xmake
xmake會自動調用conan工具去下載下傳安裝openssl庫,然後內建使用,隻需要執行xmake指令即可完成編譯。
add_requires("conan::OpenSSL/[email protected]/stable", {alias = "openssl"})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("openssl")
cmake
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/[email protected]/stable
BASIC_SETUP
BUILD missing)
add_executable(test main.c)
target_link_libraries(main ${CONAN_LIBS})
使用内建包倉庫
xmake
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 [email protected]:myrepo/xmake-repo.git")
或者直接指令行添加:
xmake repo --add my-repo [email protected]:myrepo/xmake-repo.git
關于這塊的詳細說明可以看下相關文檔:
- 遠端依賴模式
- add_requires接口說明
最後,附帶一張xmake的依賴包管理架構圖:
cmake
這塊我沒看到cmake有支援,不過cmake我用得并不多,如果有寫的不對的地方,大家可以指正。
原文出處:https://tboox.org/cn/2019/05/29/xmake-vs-cmake/