Xmake is a lightweight cross-platform build utility based on Lua.
It is very lightweight and has no dependencies because it has a built-in Lua runtime.
It uses xmake.lua to maintain project builds and its configuration syntax is very simple and readable.
We can use it to build project directly like Make/Ninja, or generate project files like CMake/Meson, and it also has a built-in package management system to help users solve the integrated use of C/C++ dependent libraries.
Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache
Although not very precise, we can still understand Xmake in the following way:
Xmake ≈ Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache
Introduction of new features
Before introducing new features, there is good news to tell you that the previous version of Xmake was included in the debian repository, and recently Xmake has entered the Fedora official repository. You can install Xmake directly on Fedora 39 through the following command.
$ sudo dnf install xmake
Many thanks to @topazus @mochaaP for their contribution to Xmake. For related information, see: #941.
Next, let’s introduce the heavyweight feature brought by the new version: XPack.
It is similar to CMake’s CPack command, which can quickly package user projects to generate installation packages in various formats.
Currently Xmake’s XPack already supports packaging in the following formats:
- nsis: executable installation package under Windows
- runself: shell self-compiled installation package
- targz: binary file tar.gz package (green version)
- zip: Binary file zip package (green version)
- srctargz: source file tar.gz package
- srczip: source file zip package
- srpm: rpm source code installation package
- rpm: rpm binary installation package
In addition to the above-mentioned supported packaging formats, package formats such as deb are also being gradually supported, and users can also configure and generate custom package format files.
XPack packaging
Here is a complete example, we can take a brief look at it first:
set_version("1.0.0")
add_rules("mode.debug", "mode.release")
includes("@builtin/xpack")
target("test")
set_kind("binary")
add_files("src/*.cpp")
xpack("test")
set_formats("nsis", "zip", "targz", "runself")
set_title("hello")
set_author("ruki")
set_description("A test installer.")
set_homepage("https://xmake.io")
set_licensefile("LICENSE.md")
add_targets("test")
add_installfiles("src/(assets/*.png)", {prefixdir = "images"})
add_sourcefiles("(src/**)")
set_iconfile("src/assets/xmake.ico")
after_installcmd(function (package, batchcmds)
batchcmds:mkdir(package:installdir("resources"))
batchcmds:cp("src/assets/*.txt", package:installdir("resources"), {rootdir = "src"})
batchcmds:mkdir(package:installdir("stub"))
end)
after_uninstallcmd(function (package, batchcmds)
batchcmds:rmdir(package:installdir("resources"))
batchcmds:rmdir(package:installdir("stub"))
end)
We introduce all configuration interfaces of xpack through includes("@builtin/xpack")
, including the xpack configuration domain and all its domain interfaces.
Then we execute:
$xmakepack
All installation packages will be generated.
Generate NSIS installation package
As long as you configure the set_formats("nsis")
format and then execute the xmake pack
command, you can generate an installation package in NSIS format.
In addition, xmake will also automatically install the tools required to generate NSIS packages to achieve true one-click packaging.
$xmakepack
note: install or modify (m) these packages (pass -y to skip confirm)?
in xmake-repo:
-> nsis 3.09
please input: y (y/n/m)
=> install nsis 3.09 .. ok
[25%]: compiling.release src\main.cpp
[37%]: compiling.release src\main.cpp
[50%]: linking.release foo.dll
[62%]: linking.release test.exe
packing build\xpack\test\test-windows-x64-v1.0.0.exe
pack ok
test-windows-x64-v1.0.0.exe
is the installation package we generated. Double-click to run it to install our binary files to the specified directory.
Add component installation
We can also add component installation commands to NSIS. Only when the user selects the specified component, its installation command will be executed.
xpack("test")
add_components("LongPath")
xpack_component("LongPath")
set_default(false)
set_title("Enable Long Path")
set_description("Increases the maximum path length limit, up to 32,767 characters (before 256).")
on_installcmd(function (component, batchcmds)
batchcmds:rawcmd("nsis", [[
${If} $NoAdmin == "false"
; Enable long path
WriteRegDWORD ${HKLM} "SYSTEM\CurrentControlSet\Control\FileSystem" "LongPathsEnabled" 1
${EndIf}]])
end)
In this example, we added an NSIS-specific custom command to support long paths.
Generate self-installation package
We can also generate self-compiled installation packages based on shell scripts. We need to configure the runself packaging format, and then add the source files that need to participate in compilation and installation through add_sourcefiles
.
Next, we need to customize the on_installcmd installation script to configure if we compile the source code package, we can simply call a built-in compilation and installation script file, or directly configure compilation and installation commands such as make install
.
For example:
xpack("test")
set_formats("runself")
add_sourcefiles("(src/**)")
on_installcmd(function (package, batchcmds)
batchcmds:runv("make", {"install"})
end)
Then, we execute the xmake pack
command to generate a self-installed xxx.gz.run package, which uses gzip compression by default.
$xmakepack
packing build/xpack/test/test-macosx-src-v1.0.0.gz.run
pack ok
We can use sh to load and run it to install our program.
$ sh ./build/xpack/test/test-macosx-src-v1.0.0.gz.run
We can also look at a more complete example:
xpack("xmakesrc")
set_formats("runself")
set_basename("xmake-v$(version)")
set_prefixdir("xmake-$(version)")
before_package(function (package)
import("devel.git")
local rootdir = path.join(os.tmpfile(package:basename()) .. ".dir", "repo")
if not os.isdir(rootdir) then
os.tryrm(rootdir)
os.cp(path.directory(os.projectdir()), rootdir)
git.clean({repodir = rootdir, force = true, all = true})
git.reset({repodir = rootdir, hard = true})
if os.isfile(path.join(rootdir, ".gitmodules")) then
git.submodule.clean({repodir = rootdir, force = true, all = true})
git.submodule.reset({repodir = rootdir, hard = true})
end
end
local extraconf = {rootdir = rootdir}
package:add("sourcefiles", path.join(rootdir, "core/**|src/pdcurses/**|src/luajit/**|src/tbox/tbox/src/demo/**"), extraconf )
package:add("sourcefiles", path.join(rootdir, "xmake/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "*.md"), extraconf)
package:add("sourcefiles", path.join(rootdir, "configure"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/*.sh"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/man/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/debian/**"), extraconf)
package:add("sourcefiles", path.join(rootdir, "scripts/msys/**"), extraconf)
end)
on_installcmd(function (package, batchcmds)
batchcmds:runv("./scripts/get.sh", {"__local__"})
end)
It is the installation package configuration script of xmake’s own source code. For more complete configuration, please refer to: xpack.lua
Here, it performs compilation and installation by calling the ./scripts/get.sh
installation script built into the source package.
Generate source code archive package
In addition, we can also configure the srczip
and srctargz
formats to generate source code compression packages. It is not a complete installation package and has no installation commands. It is only used for source code package distribution.
xpack("test")
set_formats("srczip", "srctargz")
add_sourcefiles("(src/**)")
$xmakepack
packing build/xpack/test/test-macosx-src-v1.0.0.zip ..
packing build/xpack/test/test-macosx-src-v1.0.0.tar.gz ..
pack ok
Generate binary archive package
We can also configure zip
and targz
to generate binary compressed packages. It will automatically compile all bound target target programs and package all required binary programs and library files into zip/tar.gz format.
This is usually used to create a green version of the installation package. There is no automatic installation script inside. Users need to set environment variables such as PATH themselves.
xpack("test")
set_formats("zip", "targz")
add_installfiles("(src/**)")
$xmakepack
packing build/xpack/test/test-macosx-v1.0.0.zip ..
packing build/xpack/test/test-macosx-v1.0.0.tar.gz ..
pack ok
!> It should be noted that to add binary files to the package, use add_installfiles
instead of add_sourcefiles
.
We can also use add_targets
to bind the target target programs and libraries that need to be installed. See the interface description for add_targets
below for more details.
Generate SRPM source code installation package
It can generate source code installation packages in .src.rpm
format.
We can configure add_targets to associate the targets that need to be built. In the generated srpm package, it will automatically call xmake build
and xmake install
to build and install the package.
xpack("test")
set_homepage("https://xmake.io")
set_license("Apache-2.0")
set_description("A cross-platform build utility based on Lua.")
set_formats("srpm")
add_sourcefiles("(src/**)")
add_sourcefiles("./xmake.lua")
add_targets("demo")
It will generate a spec file similar to the following, and then automatically call rpmbuild to generate the .src.rpm
package.
Name: test
Version: 1.0.0
Release: 1%{?dist}
Summary: hello
License: Apache-2.0
URL: https://xmake.io
Source0: test-linux-src-v1.0.0.tar.gz
BuildRequires: xmake
BuildRequires: gcc
BuildRequires: gcc-c++
%description
A test installer.
%prep
%autosetup -n test-1.0.0 -p1
%build
xmake build -y test
%install
xmake install -o %{buildroot}/%{_exec_prefix} test
cd %{buildroot}
find . -type f | sed 's!^\./!/!' > %{_builddir}/_installedfiles.txt
%check
%files -f %{_builddir}/_installedfiles.txt
%changelog
* Fri Dec 22 2023 ruki - 1.0.0-1
- Update to 1.0.0
We can also customize build and installation scripts through on_buildcmd
and on_installcmd
.
xpack("test")
set_homepage("https://xmake.io")
set_license("Apache-2.0")
set_description("A cross-platform build utility based on Lua.")
set_formats("srpm")
add_sourcefiles("(src/**)")
add_sourcefiles("./configure")
on_buildcmd(function (package, batchcmds)
batchcmds:runv("./configure")
batchcmds:runv("make")
end)
on_installcmd(function (package, batchcmds)
batchcmds:runv("make", {"install", "PREFIX=%{buildroot}"})
end)
Generate RPM binary installation package
The RPM package will directly generate a compiled binary installation package. xmake will automatically call the rpmbuild --rebuild
command to build the SRPM package and generate it.
In XPack, we only need to configure set_formats("rpm")
to support rpm package generation, and other configurations are exactly the same as srpm packages.
xpack("test")
set_formats("rpm")
-- TODO
Packaging command parameters
Specify packaging format
If we have configured multiple packaging formats using set_formats
in the configuration file, then xmake pack
will automatically generate packages for all these formats by default.
Of course, we can also use xmake pack --formats=nsis,targz
to selectively specify which formats of packages currently need to be packaged.
Modify the package file name
We can modify the package name through set_basename()
in the configuration file, or we can modify it through the command line.
$ xmake pack --basename="foo"
packing build/xpack/test/foo.zip ..
pack ok
Specify output directory
The default output directory is in the build directory, but we can also modify the output path.
$ xmake pack -o /tmp/output
Disable automatic build
If you are building a binary package such as NSIS, xmake pack
will automatically compile all bound target files first, and then execute the packaging logic.
But if we have already compiled it and don’t want to compile it every time, but package it directly, we can disable automatic building through the following parameters.
$ xmake pack --autobuild=n
Interface description
For more descriptions of the XPack packaging interface, see: XPack Packaging Interface Document.
Install the package locally
By default, packages configured through add_requires("xxx")
will be installed in the global directory, and different projects share these packages.
In the new version, we have added a package.install_locally
strategy, which can be configured to let xmake install the package to the current local project directory.
set_policy("package.install_locally", true)
Changelog
New features
- Add
network.mode
policy - #1433: Add
xmake pack
command to generate NSIS/zip/tar.gz/rpm/srpm/runself packages like cmake/cpack - #4435: Support batchsize for UnityBuild in Group Mode
- #4485: Support package.install_locally
- Support NetBSD
Changes
- #4484: Improve swig rule
- Improve Haiku support