Xmake integrates built-in remote package dependency management. Users simply add the packages and versions they need to the project, and then automatically download and integrate the corresponding packages into the project, and compile and link.
For example:
add_requires("libuv master", "ffmpeg", "zlib 1.20.*")
add_requires("tbox >1.6.1", {optional = true, debug = true})
add_requires("boost", {alias = "boost_context", configs = {context = true}})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("libuv", "ffmpeg", "tbox", "boost_context", "zlib")
Xmake’s package repository was designed with semantic version support and cross-platform support for dependencies. As long as the package itself supports the platform, it can be integrated, such as zlib package, used in xmake, iphoneos, android and mingw. All platforms are fully available.
Users only need to simply cut the build platform:
xmake f -p iphoneos -a arm64
xmake
note: try installing these packages (pass -y to skip confirm)?
in xmake-repo:
-> zlib 1.2.11
please input: y (y/n)
=> download https://downloads.sourceforge.net/project/libpng/zlib/1.2.11/zlib-1.2.11.tar.gz .. ok
=> install zlib 1.2.11 .. ok
You can download the corresponding package in the ‘add_requires` for the iphoneos platform. The ultimate goal of xmake is to create a cross-platform package repository. Users no longer need to find the c/c++ library, and then study the migration of various platforms. You need to simply add the package dependencies, which can be easily used on all platforms.
Of course, the current xmake official warehouse is still in the early stage of development, there are still few packages, and the supported platforms are not perfect. Therefore, here I briefly introduce how users can make and upload their own c/c++ packages. And how to submit it to our warehouse (you can also build your own private warehouse), I hope that interested partners can help to contribute a small amount of effort to jointly build and build a c/c++ dependency package ecosystem.
Before making our own package, we need to understand the structure of the next package repository, whether it is the official package repository or the self-built private package repository, the structure is the same:
xmake-repo
- packages
- t/tbox/xmake.lua
- z/zlib/xmake.lua
Through the above structure, you can see that each package will have a xmake.lua to describe its installation rules, and according to the z/zlib
two-level sub-category storage, convenient for quick retrieval.
The description rules for the package are basically done in its xmake.lua, which is similar to the xmake.lua description in the project project. The difference is that the description field only supports package()
.
However, in the project xmake.lua, you can also directly add package()
to the built-in package description, and even the package warehouse is saved, sometimes it will be more convenient.
First, let’s take a look at zlib’s description rules first. This rule can be found at xmake-repo/z/zlib/xmake.lua.
package("zlib")
set_homepage("http://www.zlib.net")
set_description("A Massively Spiffy Yet Delicately Unobtrusive Compression Library")
set_urls("http://zlib.net/zlib-$(version).tar.gz",
"https://downloads.sourceforge.net/project/libpng/zlib/$(version)/zlib-$(version).tar.gz")
add_versions("1.2.10", "8d7e9f698ce48787b6e1c67e6bff79e487303e66077e25cb9784ac8835978017")
add_versions("1.2.11", "c3e5e9fdd5004dcb542feda5ee4f0ff0744628baf8ed2dd5d66f8ca1197cb1a1")
on_install("windows", function (package)
io.gsub("win32/Makefile.msc", "%-MD", "-" .. package:config("vs_runtime"))
os.vrun("nmake -f win32\\Makefile.msc zlib.lib")
os.cp("zlib.lib", package:installdir("lib"))
os.cp("*.h", package:installdir("include"))
end)
on_install("linux", "macosx", function (package)
import("package.tools.autoconf").install(package, {"--static"})
end)
on_install("iphoneos", "android@linux,macosx", "mingw@linux,macosx", function (package)
import("package.tools.autoconf").configure(package, {host = "", "--static"})
io.gsub("Makefile", "\nAR=.-\n", "\nAR=" .. (package:build_getenv("ar") or "") .. "\n")
io.gsub("Makefile", "\nARFLAGS=.-\n", "\nARFLAGS=cr\n")
io.gsub("Makefile", "\nRANLIB=.-\n", "\nRANLIB=\n")
os.vrun("make install -j4")
end)
on_test(function (package)
assert(package:has_cfuncs("inflate", {includes = "zlib.h"}))
end)
This package rule adds installation rules to windows, linux, macosx, iphoneos, mingw and other platforms. Basically, it has achieved full platform coverage, and even some cross-compilation platforms, which is a typical example.
Of course, some packages rely on source code implementation and are not completely cross-platform, so you only need to set the installation rules for the platforms it supports.
This version mainly makes a lot of improvements to the Cuda project, and adds support for lex/yacc compilation.
It also adds custom support for link phases such as on_link
, before_link
and after_link
to the target.
Here, I would also like to thank @OpportunityLiu for support for xmake. In this version OpportunityLiu contributed a lot of code to Improve Cuda support. In addition, he helped improve xmake’s entire unit testing framework, self-updating programs, command line tab completions, and ci scripts to make xmake’s update iterations more efficient and stable.
Prior to 2.2.6, the compiler support for cuda was not perfect. At least the header file dependency detection was not provided. Therefore, if there is more cuda code, every change will compile all, not like c/c++ code. Do it to detect changes and perform incremental compilation.
In the new version, xmake has supported it, and now it is very good to handle dependencies on different platforms, which will improve the efficiency of daily compilation and development.
In the previous version, adding gencodes configuration was very cumbersome and not concise. You can look at the previous configuration:
target("cuda_console")
set_kind("binary")
add_files("src/*.cu")
add_cuflags("-gencode arch=compute_30,code=sm_30", "-gencode arch=compute_35,code=sm_35")
add_cuflags("-gencode arch=compute_37,code=sm_37", "-gencode arch=compute_50,code=sm_50")
add_cuflags("-gencode arch=compute_52,code=sm_52", "-gencode arch=compute_60,code=sm_60")
add_cuflags("-gencode arch=compute_61,code=sm_61", "-gencode arch=compute_70,code=sm_70")
add_cuflags("-gencode arch=compute_70,code=compute_70")
add_ldflags("-gencode arch=compute_30,code=sm_30", "-gencode arch=compute_35,code=sm_35")
add_ldflags("-gencode arch=compute_37,code=sm_37", "-gencode arch=compute_50,code=sm_50")
add_ldflags("-gencode arch=compute_52,code=sm_52", "-gencode arch=compute_60,code=sm_60")
add_ldflags("-gencode arch=compute_61,code=sm_61", "-gencode arch=compute_70,code=sm_70")
add_ldflags("-gencode arch=compute_70,code=compute_70")
Therefore, in order to streamline the configuration of xmake.lua, the add_cugencodes
api added to the cuda project is used to simplify the configuration. The improvements are as follows:
target("cuda_console")
set_kind("binary")
add_files("src/*.cu")
-- generate SASS code for each SM architecture
add_cugencodes("sm_30", "sm_35", "sm_37", "sm_50", "sm_52", "sm_60", "sm_61", "sm_70")
-- generate PTX code from the highest SM architecture to guarantee forward-compatibility
add_cugencodes("compute_70")
In addition, when configured as add_cugencodes("native")
, xmake will automatically detect the gencodes supported by the current device, which will be added automatically, which is more convenient and efficient.
This, thanks to the probe code provided by [OpportunityLiu] (https://github.com/OpportunityLiu) and the implementation of add_cugencodes
.
First of all, I have to admit that cmake is very powerful and has developed for so many years. The whole ecology is quite perfect and the functions are quite rich. This is not the case with xmake.
The purpose of doing xmake at the beginning was not to completely replace cmake. It didn’t make any sense. I just thought that the syntax and ease of use of cmake couldn’t satisfy me. I still prefer a simpler and more intuitive way to describe and maintain the project. Provides a near-consistent experience under the platform.
Therefore, xmake’s syntax description and experience is still very good, which is one of the biggest highlights of xmake. I have made a lot of improvements in this design, and it is easier to get started quickly in order to lower the threshold of learning and project maintenance.
Here, I only use some of the more dominant features of xmake to compare with cmake, just to highlight the advantages and ease of use of xmake in some aspects, and there is no meaning to devalue cmake.
If you have read the comparative analysis of this article, I feel that xmake is really easy to use, can meet the needs of some project maintenance, solve some pain points, and improve the efficiency of project maintenance.
I will first list some of the main basic features of the build tools. Most of the features are supported, and the advantages of xmake are mainly: syntax, package repository management, build experience.
feature | xmake | cmake |
---|---|---|
Grammar | Lua syntax, simple and intuitive, fast to get started | DSL, complex, high learning cost |
Self-built package warehouse management | Multi-warehouse support, self-built private package warehouse | Not supported |
Third Party Package Management Integration | vcpkg/conan/brew | vcpkg/conan/Other |
Build Behavior | Direct Build, No Dependencies | Generate Project Files, Call Third Party Build Tools |
Dependencies | Depends only on the build toolchain | Dependent build toolchain + third-party build tools |
Find Dependencies | Support | Support |
Compiler Feature Detection | Support | Support |
Project File Generation | Support | Support |
Cross-platform | Support | Support |
IDE/Editor Plugin | Support | Support |
Modules and Plugin Extensions | Support | Support |
target("test")
set_kind("binary")
add_files("src/main.c")
add_executable(test "")
target_sources(test PRIVATE src/main.c)
xmake supports wildcard matching, adding a batch of source files, *.c
matches all files in the current directory, **.c
matches all files in the recursive directory.
In this way, for some new files compiled in the normal project, you don’t need to modify xmake.lua every time, and automatically synchronize, which can save a lot of time.
target("test")
set_kind("binary")
add_files("src/*.c")
add_files("test/*.c", "example/**.cpp")
Xmake’s add_files()
is very flexible and powerful. It not only supports the addition of various types of source files, but also excludes certain specified files while adding them.
For example: recursively add all c files under src, but not all c files under src/impl/
.
add_files("src/**.c|impl/*.c")
For more instructions on using this interface, see the related documentation: add_files
This version mainly improves the support of remote dependencies, and adds support for clib package dependencies. In addition, xmake has been able to directly compile Qt/Android projects, and can directly generate apk packages and install them to device support.
We can create a Qt empty project first, and try to compile and generate apk, for example:
xmake create -t quickapp_qt -l c ++ appdemo
cd appdemo
xmake f -p android --ndk=~/Downloads/android-ndk-r19c/ --android_sdk=~/Library/Android/sdk/ -c
xmake
[0%]: compiling.qt.qrc src/qml.qrc
[ 50%]: ccache compiling.release src/main.cpp
[100%]: linking.release libappdemo.so
[100%]: generating.qt.app appdemo.apk
Then install to the device:
xmake install
installing appdemo ...
installing build/android/armv7-a/release/appdemo.apk ..
success
install ok!👌
Very simple, we can look at its xmake.lua description, in fact, there is no difference between compiling and maintaining the Qt project on the pc. The exact same description file is just switched to the android platform when compiling.
add_rules("mode.debug", "mode.release")
target("appdemo")
add_rules("qt.application")
add_headerfiles("src/*.h")
add_files("src/*.cpp")
add_files("src/qml.qrc")
add_frameworks("QtQuick")
This version took more than four months to refactor and improve the package dependency management. The official repository added common packages such as mysql and ffmpeg, and added a lot of features.
add_requires("libuv master", "ffmpeg", "zlib 1.20.*")`
xmake will find and install packages from the official package repository (xmake-repo).
xmake adds built-in support for third-party package managers, explicitly specifying packages in other package managers through package namespaces,
and it currently supports conan::
, brew::
and vcpkg::
packages.
add_requires("brew::zlib", {alias = "zlib"}})
add_requires("brew::pcre2/libpcre2-8", {alias = "pcre2"}})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("pcre2", "zlib")
add_requires("vcpkg::zlib", "vcpkg::pcre2")
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("vcpkg::zlib", "vcpkg::pcre2")
The new version implements the conan generator to integrate the package information in the conan. It is also very convenient to use in xmake, and can pass all the configuration parameters of the conan package.
add_requires("conan::zlib/1.2.11@conan/stable", {alias = "zlib", debug = true})
add_requires("conan::OpenSSL/1.0.2n@conan/stable", {alias = "openssl", configs = {options = "OpenSSL:shared=True"}})
target("test")
set_kind("binary")
add_files("src/*.c")
add_packages("openssl", "zlib")
After executing xmake to compile:
ruki:test_package ruki$ xmake
checking for the architecture ... x86_64
checking for the Xcode directory ... /Applications/Xcode.app
checking for the SDK version of Xcode ... 10.14
note: try installing these packages (pass -y to skip confirm)?
-> conan::zlib/1.2.11@conan/stable (debug)
-> conan::OpenSSL/1.0.2n@conan/stable
please input: y (y/n)
=> installing conan::zlib/1.2.11@conan/stable .. ok
=> installing conan::OpenSSL/1.0.2n@conan/stable .. ok
[ 0%]: ccache compiling.release src/main.c
[100%]: linking.release test