Skip to content

Using Custom Build Rules in xmake

After version 2.1.9, xmake not only natively supports building multiple language files, but also allows users to implement complex unknown file builds through custom build rules.

For specific usage instructions, please refer to the relevant documentation: Rule Usage Manual

General Rules

We can extend build support for other files by pre-setting the file extensions supported by rules:

lua
-- Define a build rule for markdown files
rule("markdown")
    set_extensions(".md", ".markdown")
    on_build(function (target, sourcefile)
        os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. ".html"))
    end)

target("test")
    set_kind("binary")
    
    -- Make test target support markdown file build rules
    add_rules("markdown")

    -- Add markdown file builds
    add_files("src/*.md")
    add_files("src/*.markdown")

We can also specify some scattered other files to be processed as markdown rules:

lua
target("test")
    -- ...
    add_files("src/test/*.md.in", {rule = "markdown"})

Note: Rules specified through add_files("*.md", {rule = "markdown"}) have higher priority than rules set by add_rules("markdown").

Dependent Builds

We can also implement cascading builds of rules. For example, after building the man rule, continue to call the markdown rule to implement cascading builds:

lua
rule("man")
    add_imports("core.project.rule")
    on_build(function (target, sourcefile)
        rule.build("markdown", target, sourcefile)
    end)

Among them, add_imports is used to pre-import extension modules, which can be directly used in multiple custom scripts. For specific instructions, see: add_imports Documentation

Multi-file Builds

For some files, you need to support multi-file builds to generate a single object mode, which can be implemented through on_build_all:

lua
rule("man")
    on_build_all(function (target, sourcefiles)
        -- build some source files
        for _, sourcefile in ipairs(sourcefiles) do
            -- ...
        end
    end)

target("test")
    -- ...
    add_files("src/test/*.doc.in", {rule = "man"})

Clean and Install

We can use on_clean, on_install to implement custom rule cleanup and installation logic, processing one source file at a time, for example:

lua
rule("markdown")
    on_build(function (target, sourcefile)
        os.cp(sourcefile, path.join(target:targetdir(), path.basename(sourcefile) .. ".html"))
    end)
    on_clean(function (target, sourcefile)
        os.rm(path.join(target:targetdir(), path.basename(sourcefile) .. ".html"))
    end)
    on_install(function (target, sourcefile)
        import("core.base.option")
        os.cp(path.join(target:targetdir(), path.basename(sourcefile) .. ".html"), option.get("outputdir"))
    end)

Finally, here's a complete example for reference: Rule Usage Example