Xmake is a lightweight cross-platform build tool based on Lua, using xmake. Lua maintenance project construction, compared to makefile/ cmakelists.txt configuration syntax is more concise and intuitive, very friendly to beginners, in a short time can be quickly started. Can let the user focus more energy on the actual project development.

In this release, we have added a number of new features, including compilation support for Vala and Metal languages, as well as improved package dependency management, which supports locking and updating of dependencies like NPM /package.lock, so that users’ projects are not affected by changes in upstream package repositories.

In addition, we also provide some practical rules, such as utils. Bin2c allows users to easily and quickly embed some binary resource files into the code, and obtain relevant data in the way of header files.

  • Program source code
  • The official documentation
  • An introductory course

New Features

Added Vala language support

With this release, we can start to support building Vala programs by applying the add_rules(” Vala “) rule.

At the same time, we need to add some dependency packages, of which the glib package is necessary because vala itself also uses it.

Add_values (“vala.packages”) is used to tell ValAC which packages are required for the project. It introduces the Vala API for the packages, but the integration of the packages’ dependencies requires(“lua”) to download the integration.

Such as:

add_rules("mode.release"."mode.debug")

add_requires("lua"."glib")

target("test")
    set_kind("binary")
    add_rules("vala")
    add_files("src/*.vala")
    add_packages("lua"."glib")
    add_values("vala.packages"."lua")
Copy the code

More examples: Vala Examples

Added package dependency locking support

This feature is similar to package.lock for NPM, cargo for cargo.

For example, if we reference some packages, by default xmake will automatically pull the latest version of the package every time if the version is not specified, for example:

add_requires("zlib")
Copy the code

However, if the upstream package repository changes, such as a new 1.2.11 version of Zlib, or the installation script changes, the user’s dependency package will change.

This can easily lead to projects that were originally compiled, unstable due to changes in dependencies, failed compilations, and so on.

To ensure that a user’s project uses a fixed package each time, we can enable package-dependent locking by configuring the following.

set_policy("package.requires_lock".true)
Copy the code

This is a global setting and must be set to the global root scope. If enabled, xmake will automatically generate a configuration file that xmake-requires. Lock.

It contains information about all the packages that the project depends on, as well as the version of the current package.

{
    __meta__ = {
        version = "1.0"},"macosx|x86_64"] = {["cmake#31fecfc4"] = {
            repo = {
                branch = "master",
                commit = "4498f11267de5112199152ab030ed139c985ad5a",
                url = "https://github.com/xmake-io/xmake-repo.git"
            },
            version = "3.21.0"},"glfw#31fecfc4"] = {
            repo = {
                branch = "master",
                commit = "eda7adee81bac151f87c507030cc0dd8ab299462",
                url = "https://github.com/xmake-io/xmake-repo.git"
            },
            version = "3.3.4"},"opengl#31fecfc4"] = {
            repo = {
                branch = "master",
                commit = "94d2eee1f466092e04c5cf1e4ecc8c8883c1d0eb",
                url = "https://github.com/xmake-io/xmake-repo.git"}}}}Copy the code

Of course, we can also execute the following command to force the upgrade package to the latest version.

$ xmake require --upgradeupgrading packages .. Zlib: 1.2.10 -> 1.2.11 1 Package is upgrade!Copy the code

Option supports runtime detection of code snippets

Option provides add_CSNIPpets/add_Cxxpets interfaces for quickly detecting whether a particular section of C/C ++ code has been compiled. If it has been compiled, the corresponding option option is enabled.

However, while previous versions only provided compile-time detection, in the new version we have also added runtime detection support.

We can try to run the detection and capture the output by setting {tryrun = true} and {output = true} parameters.

Try to run detection

Set tryRun to try to run to test

option("test")
    add_cxxsnippets("HAS_INT_4"."return (sizeof(int) == 4)? 0:1;", {tryrun = true})
Copy the code

If the compile runs successfully, the test option is enabled.

The runtime detects and captures the output

Setting output also tries to detect, and additionally captures the output of the run.

option("test")
    add_cxxsnippets("INT_SIZE".'printf("%d", sizeof(int)); return 0; ', {output = true, number = true})
Copy the code

If the compilation runs successfully, the test option is enabled and the corresponding output is retrieved as the value of option.

Note: Set to capture output, current option cannot set additional snippets

We can also get the output bound to option from is_config.

if is_config("test"."8") tben
    -- xxx
end
Copy the code

In addition, we have also improved the auxiliary detection interface of includes(” check_CSNIPpets “) to support runtime detection.

includes("check_csnippets.lua")

target("test")
    set_kind("binary")
    add_files("*.c")
    add_configfiles("config.h.in")

    check_csnippets("HAS_INT_4"."return (sizeof(int) == 4)? 0:1;", {tryrun = true})
    check_csnippets("INT_SIZE".'printf("%d", sizeof(int)); return 0; ', {output = true, number = true})
    configvar_check_csnippets("HAS_LONG_8"."return (sizeof(long) == 8)? 0:1;", {tryrun = true})
    configvar_check_csnippets("PTR_SIZE".'printf("%d", sizeof(void*)); return 0; ', {output = true, number = true})
Copy the code

If capture output is enabled, ${define PTR_SIZE} in config.h.N automatically generates #define PTR_SIZE 4.

#define PTR_SIZE “4”

Quickly embed binary resource files into code

Using the utils.bin2c rule, we can introduce binaries into a project and make them available to developers as C/C ++ header files to retrieve data from these files.

For example, we can embed some PNG/JPG resource files into the code in the project.

target("console")
    set_kind("binart")
    add_rules("utils.bin2c", {extensions = {".png".".jpg"}})
    add_files("src/*.c")
    add_files("res/*.png"."res/*.jpg")
Copy the code

Note: The extensions setting is optional and the default extension name is.bin

You can then use #include “filename.pnp.h” and Xmake will automatically generate the corresponding header file for you and add the corresponding search directory.

static unsigned char g_png_data[] = {
    #include "image.png.h"
};

int main(int argc, char** argv)
{
    printf("image.png: %s, size: %d\n", g_png_data, sizeof(g_png_data));
    return 0;
}
Copy the code

The generated header file has similar content:

cat build/.gens/test/macosx/x86_64/release/rules/c++/bin2c/image.png.h
  0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x78, 0x6D, 0x61, 0x6B, 0x65, 0x21, 0x0A, 0x00
Copy the code

Added support for iOS/macOS application Metal compilation

We know that the xcode.application rule compiles iOS/macOS applications, generates.app/.ipa packages, and does the signing at the same time.

The xcode. Metal rule is associated with the xcode. Application rule to support metal compilation by default.

Xmake automatically compiles.metal and packages it to generate default.metallib, which is automatically built into.app/.ipa.

If the user’s Metal is accessed through [_device newDefaultLibrary], it will be automatically supported, just like compiling with Xcode.

Here is a complete example of our: project.

add_rules("mode.debug"."mode.release")

target("HelloTriangle")
    add_rules("xcode.application")
    add_includedirs("Renderer")
    add_frameworks("MetalKit")
    add_mflags("-fmodules")
    add_files("Renderer/*.m"."Renderer/*.metal") ------- Add the Metal file
    if is_plat("macosx") then
        add_files("Application/main.m")
        add_files("Application/AAPLViewController.m")
        add_files("Application/macOS/Info.plist")
        add_files("Application/macOS/Base.lproj/*.storyboard")
        add_defines("TARGET_MACOS")
        add_frameworks("AppKit")
    elseif is_plat("iphoneos") then
        add_files("Application/*.m")
        add_files("Application/iOS/Info.plist")
        add_files("Application/iOS/Base.lproj/*.storyboard")
        add_frameworks("UIKit")
        add_defines("TARGET_IOS")
Copy the code

For example, on macOS, once compiled and run, it will render the desired effect through Metal.

If our project does not use the default Metal Library, we can also use the utils.bin2c rule mentioned above to embed it in the code base as a source file, for example:

add_rules("utils.bin2c", {extensions = ".metal"})
add_files("Renderer/*.metal")
Copy the code

Then in the code, we can access:

static unsigned char g_metal_data[] = {
    #include "xxx.metal.h"
};

id<MTLLibrary> library = [_device newLibraryWithSource:[[NSString stringWithUTF8String:g_metal_data]] options:nil error:&error];
Copy the code

Improved add_repositories

If we were using a local repository built into the project, we had previously introduced it by add_repositories(“myrepo Repodir “).

However, it is not based on a relative directory to the current xmake.lua file directory, as add_files() is, and there is no automatic path conversion, so it is prone to problems where the repO cannot be found.

Therefore, we improved it to specify the corresponding root directory location with an additional rootdir parameter, such as the script directory relative to the current xmake.lua.

add_repositories("myrepo repodir", {rootdir = os.scriptdir()})
Copy the code

Os.cp supports symbolic links

In previous versions, the os.cp interface did not handle symlink copying well. It automatically expanded the link and copied the actual file content, which only caused the symlink to be lost after copying.

{symlink = true} if you want to keep the symlink after copying, just set the following parameter: {symlink = true}

os.cp("/xxx/symlink"."/xxx/dstlink", {symlink = true})
Copy the code

Easier compilation of automatically generated code

Sometimes, there is a need to automatically generate some source files for later code compilation before compilation. But because the files add_files adds are already identified at compile time, they cannot be added dynamically during compile (because parallel compilation is required).

Therefore, to implement this requirement, we usually need to define a custom rule, which actively calls the compiler module to handle the compilation of generated code, the injection of object files, dependency updates, etc.

This isn’t a big problem for xmake developers themselves, but it’s still a bit cumbersome for users to get started with.

In the new release, we improved support for add_files and added {always_added = true} configuration to tell Xmake that we always need to add the specified source file, even if it doesn’t exist yet.

This way we can rely on xmake’s default compilation process to compile automatically generated code, like this:

add_rules("mode.debug"."mode.release")

target("autogen_code")
    set_kind("binary")
    add_files("$(buildir)/autogen.cpp", {always_added = true})
    before_build(function (target)
        io.writefile("$(buildir)/autogen.cpp".[[ #include 
      
        using namespace std; int main(int argc, char** argv) { cout << "hello world!" << endl; return 0; } ]]
      )
    end)
Copy the code

No additional rule definitions are required, just compile order and generate code files at the correct stages.

However, we also need to note that we cannot use pattern matching in add_files because the currently auto-generated source file may not yet exist. We can only explicitly add each source file path.

Update the content

New features

  • #1534: Added support for Vala language
  • #1544: Add the utils.bin2c rule to automatically generate.h headers from binary resource files and import them into C/C++ code
  • #1547: Option/Snippets allows you to run detection mode and get the output
  • #1567: Added xmake-requires. Lock package dependency locking support
  • #1597: Support for compiling metal files into metallib, and improved xcode.application rules to generate built-in default.metallib into app

To improve the

  • #1540: Better and easier compilation of automatically generated code
  • #1578: Improved add_Repositories to better support relative paths
  • #1582: Improved installation and os.cp support for symbolic links

Bugs fix

  • #1531: Fixes the targets load failure error message