This is a mirror page, please see the original page:

https://xmake.io/#/package/local_3rd_source_library

Integrate CMake source library

After version 2.5.8, we can also directly integrate the source library with CMakeLists.txt in our project through the package mode of xmake, instead of downloading and installing it remotely.

Related issues: #1714

For example, we have the following project structure:

├── foo
│ ├── CMakeLists.txt
│ └── src
│ ├── foo.c
│ └── foo.h
├── src
│ └── main.c
├── test.lua
└── xmake.lua

The foo directory is a static library maintained by cmake, and the root directory is maintained by xmake. We can define the package("foo") package in xmake.lua to describe how to build the foo code library.

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

package("foo")
    add_deps("cmake")
    set_sourcedir(path.join(os.scriptdir(), "foo"))
    on_install(function (package)
        local configs = {}
        table.insert(configs, "-DCMAKE_BUILD_TYPE=" .. (package:debug() and "Debug" or "Release"))
        table.insert(configs, "-DBUILD_SHARED_LIBS=" .. (package:config("shared") and "ON" or "OFF"))
        import("package.tools.cmake").install(package, configs)
    end)
    on_test(function (package)
        assert(package:has_cfuncs("add", {includes = "foo.h"}))
    end)
package_end()

add_requires("foo")

target("demo")
    set_kind("binary")
    add_files("src/main.c")
    add_packages("foo")

Among them, we set the code directory location of the foo package through set_sourcedir(), and then import the auxiliary module of package.tools.cmake through import to call cmake to build the code, xmake will automatically obtain the generated libfoo.a and the corresponding header document.

!> If only the local source code is integrated, we don't need to set additional add_urls and add_versions.

For the configuration description of the package, see: Package description description.

After defining the package, we can integrate it with add_requires("foo") and add_packages("foo"), just like integrating remote packages.

In addition, on_test is optional. If you want to strictly check whether the package is compiled and installed successfully, you can do some tests in it.

For a complete example, see: Library with CMakeLists

Integrate Meson source library

xmake supports the integration of more third-party source code libraries maintained by other build systems, such as meson. You only need to import and use the package.tools.meson auxiliary building module to call meson to build them.

For example, we select a package built with meson from the xmake-repo repository as an example:

package("harfbuzz")
    set_sourcedir(path.join(os.scriptdir(), "3rd/harfbuzz"))

    add_deps("meson")
    if not is_plat("windows") then
        add_deps("freetype")
    end
    on_load("windows", "linux", "macosx", function (package)
        if package:config("icu") then
            package:add("deps", "icu4c")
        end
    end)

    on_install("windows", "linux", "macosx", function (package)
        local configs = {"-Dtests=disabled", "-Ddocs=disabled", "-Dbenchmark=disabled", "-Dcairo=disabled", "-Dfontconfig=disabled", "-Dglib=disabled", "-Dgobject= disabled"}
        table.insert(configs, "-Ddefault_library=" .. (package:config("shared") and "shared" or "static"))
        if package:is_plat("windows") then
            table.insert(configs, "-Dfreetype=disabled")
        end
        import("package.tools.meson").install(package, configs)
    end)

    on_test(function (package)
        assert(package:has_cfuncs("hb_buffer_add_utf8", {includes = "harfbuzz/hb.h"}))
    end)

Integrate autoconf source library

We can also use package.tools.autoconf to locally integrate third-party code libraries maintained by autoconf.

package("pcre2")

    set_sourcedir(path.join(os.scriptdir(), "3rd/pcre2"))

    add_configs("jit", {description = "Enable jit.", default = true, type = "boolean"})
    add_configs("bitwidth", {description = "Set the code unit width.", default = "8", values ​​= {"8", "16", "32"}})

    on_load(function (package)
        local bitwidth = package:config("bitwidth") or "8"
        package:add("links", "pcre2-" .. bitwidth)
        package:add("defines", "PCRE2_CODE_UNIT_WIDTH=" .. bitwidth)
        if not package:config("shared") then
            package:add("defines", "PCRE2_STATIC")
        end
    end)

    on_install("macosx", "linux", "mingw", function (package)
        local configs = {}
        table.insert(configs, "--enable-shared=" .. (package:config("shared") and "yes" or "no"))
        table.insert(configs, "--enable-static=" .. (package:config("shared") and "no" or "yes"))
        if package:debug() then
            table.insert(configs, "--enable-debug")
        end
        if package:config("pic") ~= false then
            table.insert(configs, "--with-pic")
        end
        if package:config("jit") then
            table.insert(configs, "--enable-jit")
        end
        local bitwidth = package:config("bitwidth") or "8"
        if bitwidth ~= "8" then
            table.insert(configs, "--disable-pcre2-8")
            table.insert(configs, "--enable-pcre2-" .. bitwidth)
        end
        import("package.tools.autoconf").install(package, configs)
    end)

    on_test(function (package)
        assert(package:has_cfuncs("pcre2_compile", {includes = "pcre2.h"}))
    end)

Both package.tools.autoconf and package.tools.cmake modules can support cross-compilation platforms and toolchains such as mingw/cross/iphoneos/android, xmake will automatically pass the corresponding toolchain into it, and the user does not need to do Anything else.

Integrated Scons source library

We can also use package.tools.scons to locally integrate third-party code libraries maintained by Scons.

package("godotcpp")

    set_sourcedir(path.join(os.scriptdir(), "3rd/godotcpp"))

    add_deps("scons")

    add_includedirs("include", "include/core", "include/gen")

    on_install("linux", "windows", "macosx", "mingw", "cygwin", "iphoneos", "android", "msys", function (package)
        local configs = {"generate_bindings=yes"}
        table.insert(configs, "bits=" .. ((package:is_arch("x64") or package:is_arch("x86_64")) and "64" or "32"))
        if package:is_plat("windows") then
            io.replace("SConstruct", "/MD", "/" .. package:config("vs_runtime"), {plain = true})
        end

        - this fixes an error on ios and osx (https://godotengine.org/qa/65616/problems-compiling-gdnative-c-example-on-osx)
        if package:is_plat("macosx", "iphoneos") then
            io.replace("SConstruct", "-std=c++14", "-std=c++17", {plain = true})
        end

        - fix to use correct ranlib, @see https://github.com/godotengine/godot-cpp/issues/510
        if package:is_plat("android") then
            io.replace("SConstruct",
                [[env['AR'] = toolchain + "/bin/" + arch_info['tool_path'] + "-ar"]],
                [[env['AR'] = toolchain + "/bin/" + arch_info['tool_path'] + "-ar"
    env['RANLIB'] = toolchain + "/bin/" + arch_info['tool_path'] + "-ranlib"]], {plain = true})
        end

        import("package.tools.scons").build(package, configs)
        os.cp("bin/*." .. (package:is_plat("windows") and "lib" or "a"), package:installdir("lib"))
        os.cp("include/core/*.hpp", package:installdir("include/core"))
        os.cp("include/gen/*.hpp", package:installdir("include/gen"))
        os.cp("godot-headers/android", package:installdir("include"))
        os.cp("godot-headers/arvr", package:installdir("include"))
        os.cp("godot-headers/gdnative", package:installdir("include"))
        os.cp("godot-headers/nativescript", package:installdir("include"))
        os.cp("godot-headers/net", package:installdir("include"))
        os.cp("godot-headers/pluginscript", package:installdir("include"))
        os.cp("godot-headers/videodecoder", package:installdir("include"))
        os.cp("godot-headers/*.h", package:installdir("include"))
    end)

Integrated makefile source library

Use Nmake

We can also use package.tools.nmake to locally integrate third-party code libraries maintained by nmake.

nmake.install will automatically bind the msvc build environment of the current user to ensure that the user can successfully call nmake.exe, msbuild and cl.exe and other programs.

package("libxml2")

    set_sourcedir(path.join(os.scriptdir(), "3rd/libxml2"))

    add_includedirs("include/libxml2")
    if is_plat("windows") then
        add_syslinks("wsock32", "ws2_32")
    end

    on_load("windows", function (package)
        if not package:config("shared") then
            package:add("defines", "LIBXML_STATIC")
        end
    end)

    on_install("windows", function (package)
        os.cd("win32")
        os.vrun("cscript configure.js iso8859x=yes iconv=no compiler=msvc cruntime=/%s debug=%s prefix=\"%s\"", package:config("vs_runtime"), package:debug( ) and "yes" or "no", package:installdir())
        import("package.tools.nmake").install(package, {"/f", "Makefile.msvc"})
        os.tryrm(path.join(package:installdir("lib"), "libxml2_a_dll.lib"))
        if package:config("shared") then
            os.tryrm(path.join(package:installdir("lib"), "libxml2_a.lib"))
        else
            os.tryrm(path.join(package:installdir("lib"), "libxml2.lib"))
            os.tryrm(path.join(package:installdir("bin"), "libxml2.dll"))
        end
    end)

    on_test(function (package)
        assert(package:has_cfuncs("xmlNewNode", {includes = {"libxml/parser.h", "libxml/tree.h"}}))
    end)

Use GnuMake

We can also use package.tools.make to locally integrate third-party code libraries maintained by gnumake.

package("openssl")

    set_sourcedir(path.join(os.scriptdir(), "3rd/openssl"))

    add_links("ssl", "crypto")
    if is_plat("linux", "cross") then
        add_syslinks("dl")
    end

    on_install("linux", "macosx", function (package)
        - https://wiki.openssl.org/index.php/Compilation_and_Installation#PREFIX_and_OPENSSLDIR
        os.vrun("./config %s --openssldir=\"%s\" --prefix=\"%s\"", package:debug() and "--debug" or "", package:installdir (), package:installdir())
        import("package.tools.make").install(package)
    end)

    on_test(function (package)
        assert(package:has_cfuncs("SSL_new", {includes = "openssl/ssl.h"}))
    end)

!> We can also directly use os.vrunv("make", {}) to call the make/gmake program to build the library.

Integrate GN source library

We can also use package.tools.gn to natively integrate third-party code maintained by GN.

package("skia")

     set_sourcedir(path.join(os.scriptdir(), "3rd/openssl"))

     add_deps("gn", "ninja")
     add_deps("python", {kind = "binary"})

     on_install("linux", "macosx", "windows", function (package)
         import("package.tools.gn").install(package)
     end)

     on_test(function (package)
         -- TODO
     end)

Here is the complete script example: Skia with GN