Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Grzegorz 'baziorek' Bazior
Inne artykuły

XMake: Uniwersalny System Budowania Projektów z Managerem Pakietów

[artykuł] Artykuł omawia XMake, narzędzie do budowania projektów programistycznych wspierające wiele języków i platform, wyróżniające się wbudowanym systemem zarządzania pakietami. Wyjaśniono jego podstawowe funkcje, sposób użycia oraz korzyści z integracji różnych środowisk programistycznych.

Intro

xmake jest wieloplatrofmowym narzędziem do budowania projektów napisanych w różnych językach oprogramowania o składni opartej na https://www.lua.org/. Podobnie jak CMake generuje narzędzia do budowania, z tą różnicą, że ma bardziej ludzką składnię. Ponadto przy pomocy xmake'a można zaimportować projekt CMake'a i innych popularnych systemów budowania. Kolejną zaletą narzędzia jest to, że posiada on wbudowany manager pakietów. Na swojej oficjalnej stronie chwalą się szybkością jak manager budowania Ninja, który słynie z szybkości.

W nieniejszym artykule skupię się na użyciu narzędzia xmake przez programistę C++. Mimo iż xmake jest wieloplatformowe tak bardzo, że działa nawet na mało popularnych systemach, to jednak pisząc ten artykuł używałem systemu Linux (dystrybucji opartej na Ubuntu).

Narzędzie to ma bardzo dopracowaną dokumentację, bardzo długi i obszerny tutorial jak zacząć, jak również przykłady. Mimo iż nie jest to tak popularne jak CMake, to zawiera bardzo dużo możliwości, których nie jestem w stanie przedstawić w artykule, skupiając się jedynie na wybranych pod ogólnego programistę C++.

Narzędzie ma bardzo duże możliwości, nie tylko budowania, ale też uruchamiania zbudowanego programu, jak również uruchamiania testów i znacznie, znacznie, znacznie więcej możliwości.

Instalacja

Narzędzie to instaluje się zależnie od platformy. Instrukcja znajduje się w oficjalnym tutorialu. Przykładowo dla dystrybucji opartej na Ubuntu instalacja odbywa się tak:
sudo add-apt-repository ppa:xmake-io/xmake
sudo apt update
sudo apt install xmake
Z kolei na dystrybucjach opartych na Archu:
sudo pacman -S xmake


Aktualizacja

Zaletą tego narzędzie, jest fakt, że jest ono samo-aktualizujące przy pomocy wbudowanej komendy, przykładowo:
xmake update
# można też podać konkretną wersję:
xmake update 2.7.1

Integracja z IDE

Narzędzie posiada wtyczki do integracji z CLion, VScode, QT Creatora, czy edytor vim i innymi.

Używanie narzędzia xmake

Obecnie narzędzie wspiera projekty korzystające z następujących języków programowania:
  • C++
  • C
  • Objective-C and Objective-C++
  • Swift
  • Assembly
  • Golang
  • Rust
  • Dlang
  • Fortran
  • Cuda
  • Zig
  • Vala
  • Pascal
  • Nim

Narzędzie jest dość łatwe w użyciu. W swoim projekcie możemy dodać plik
xmake.lua
, lub skorzystać z możliwości wygenerowania projektu.

Ciekawą funkcjonalnością xmake'a jest możliwość budowania projektów posiadających jedynie pliki źródłowe (nie zawierających pliku konfiguracyjnego xmake, oraz też innych plików konfiguracyjnych). Wystarczy, że w katalogu zawołamy
xmake
, po czym zostaniemy spytani czy na pewno. Wg twórców ten mechanizm sobie radzi. Po szczegóły odsyłam do dokumentacji.

Jego kolejną ciekawą funkcjonalnością jest możliwość wołania innych systemów do budowania, nie tylko CMake'a (szczegóły), ale również:
  • Autotools (wsparcie dla cross-compiling z Xmake)
  • XCodeBuild
  • CMake (wsparcie dla cross-compiling z Xmake)
  • Make
  • MSBuild
  • Scons
  • Meson
  • Bazel
  • NdkBuild
  • Ninja

Generowanie projektu

Aby utworzyć projekt należy użyć komendy:
xmake create -l c++ -t console "Pierwszy"
# alternatywnie do powyższego:
xmake create --language=c++ --template=console "Pierwszy"

Dla powyższej komendy został wygenerowany następujący plik
xmake.lua
:
add_rules("mode.debug", "mode.release")

target("Pierwszy")
    set_kind("binary")
    add_files("src/*.cpp")

-- oraz wiele innych komentarzy z przydatnymi komendami xmake

Możliwe jest wiele różnych szablonów projektów, m.in.:
  • console
  • shared
  • static
  • qt.widgetapp (tylko c++)
Jak widać
xmake
 umożliwia generowanie projektów z wsparciem biblioteki QT (jest znacznie więcej opcji generacji), jak również do pewnych narzędzi programistycznych.
Listę szablonów można znaleźć wpisując:
xmake create --help


Przykładowe używanie xmake

Załużmy, że mamy już gotowy projekt (może być wygenerowany powyższymi komendami), teraz czas na przykładowe komendy:

Budowanie projektu z xmake

Odbywa się to przez zawołanie po prostu:
xmake
# alternatywnie:
xmake build
# a jeśli chcemy tylko nasz wygenerowany wcześniej projekt, a nie wszystkie targety:
xmake build Pierwszy
Domyślnie pliki wynikowe zostaną umieszczone w katalogu
./build/


Jeśli potrzebujemy przebudować projekt możemy zawołać:
xmake --rebuild
# alternatywnie:
xmake -r

Uruchomienie programu przez xmake

Aby uruchomić jeden z celów (ang. target) wystarczy napisać:
xmake run

a, jeśli mamy więcej projektów możemy łatwo wskazać docelowy:
xmake run Pierwszy

Mamy też możliwość uruchomienia wszystkich celów:
xmake run --all
# alternatywnie:
xmake run -a
# alternatywnie zamiast całego run:
xmake r -a
Kolejną wygodą jest możliwość przekazania argumentów uruchomienia, które podajemy za nazwą targetu:
xmake r Pierwszy argumen1 argument2 "setka argumentow"


Czasami programista musi skorzystać z możliwości debugowania, co jest też możliwe przez narzędzie
xmake
:
xmake run --debug Pierwszy
# alternatywnie:
xmake run -d Pierwszy argument1 argument2

Czyszczenie zbudowanych plików

xmake clean
# lub krócej:
xmake c

Łatwość w konfiguracji platformy

Łatwo możemy zmienić konfiguracje do budowania. Przykładowo aby zmienić tryb między debug/release piszemy:
xmake config --mode=debug
# można też krócej:
xmake f --mode=debug
# lub jeszcze krócej:
xmake f -m debug
Po zmianie konfiguracji po prostu budujemy ponownie projekt.

Możemy też w łatwy sposób skompilować projekt pod inną platformę, w tym celu zmieniamy konfigurację:
xmake config --plat=windows --arch=x86 --mode=debug
# lub krócej:
xmake f -p windows -a x86 -m debug

Więcej opcji konfiguracji możemy znaleźć w standardowym
--help
 dla podkomendy
config
 czyli:
xmake config --help

ale mamy też możliwość wejścia w konfiguracyjne menu, przez zawołanie:
xmake config --menu

Jego możliwości widać na obrazku:
Warto wspomnieć, że można tworzyć własne opcje (ang. option), które można ustawiać z poziomu menu.

Wbudowane typy projektów

  • Biblioteka statyczna
  • Biblioteka dynamiczna
  • Aplikacja konsolowa
  • Moduły C++20
  • Program korzystający z Cuda
  • Aplikacja Qt
  • WDK Driver (umdf/kmdf/wdm)
  • Aplikacja WinSDK
  • Aplikacja MFC
  • Aplikacja iOS/MacOS (Support .metal)
  • Framework and Bundle Program (iOS/MacOS)
  • Moduły SWIG (Lua, python, ...)
  • Moduły Luarocks
  • Protobuf program
  • Lex/yacc program
Oczywiście można również tworzyć własne typy.

Obsługiwane platformy dla xmake

Mamy możliwość skonfigurowania targetów na popularne platformy (pełna lista platform i możliwych konfiguracji):
  • Windows
  • macOS
  • Linux
  • *BSD
  • Android
  • iOS
  • WatchOS
  • AppleTVOS
  • MSYS
  • MinGW
  • Cygwin
  • Wasm
  • Cross (cross-toolchains)
Również na różne architektury np.:
x86
, czy
arm64
.

Możemy sprawdzić listę dostępnych narzędzi programistycznych (ang. toolchains):
$ xmake show -l toolchains
xcode          Xcode IDE
vs             VisualStudio IDE
yasm           The Yasm Modular Assembler
clang          A C language family frontend for LLVM
go             Go Programming Language Compiler
dlang          D Programming Language Compiler
gfortran       GNU Fortran Programming Language Compiler
zig            Zig Programming Language Compiler
sdcc           Small Device C Compiler
cuda           CUDA Toolkit
ndk            Android NDK
rust           Rust Programming Language Compiler
llvm           A collection of modular and reusable compiler and toolchain technologies
cross          Common cross compilation toolchain
nasm           NASM Assembler
gcc            GNU Compiler Collection
mingw          Minimalist GNU for Windows
gnu-rm         GNU Arm Embedded Toolchain
envs           Environment variables toolchain
fasm           Flat Assembler
tinycc         Tiny C Compiler
emcc           A toolchain for compiling to asm.js and WebAssembly
icc            Intel C/C++ Compiler
ifort          Intel Fortran Compiler
muslcc         The musl-based cross-compilation toolchain
fpc            Free Pascal Programming Language Compiler
wasi           WASI-enabled WebAssembly C/C++ toolchain
nim            Nim Programming Language Compiler
circle         A new C++20 compiler
armcc          ARM Compiler Version 5 of Keil MDK
armclang       ARM Compiler Version 6 of Keil MDK
Mamy też możliwość utworzyć własnego toolchaina, czy napisać składowe istniejącego (np. kompilator).

Zawartość pliku xmake.lua

Najprostrza zawartość pliku
xmake.lua
 wygląda w następujący sposób:
target("Pierwszy")
    set_kind("binary")
    add_files("src/*.cpp")

Dodatkowe możliwości konfiguracyjne

Dodajemy je pod źródłem np.:
target("Pierwszy")
    set_kind("binary")
    -- tutaj dodajemy

Dodawanie plików po wzorcu

add_files("src/*.cpp")


Dodawanie stałych czasu kompilacji (define)

add_defines("DEBUG")


Dodawanie ścieżki z nagłówkami

add_includedirs("exe")


Instrukcje warunkowe

    if is_mode("debug") then
        -- co robimy przy spelnionym warunku
    end

Dodawanie katalogu zawierającego pliki źródłowe do pod-projektu

includes("src")

Można też wskazać plik podprojektu:
includes("src/xmake.lua")

Można też rekursywnie:
includes("**/xmake.lua")

Włączenie wbudowanych funkcji, przykładowo:
includes("@builtin/qt")
includes("@builtin/check")
-- alternatywnie możemy dodać tylko konkretny plik:
includes("@builtin/check/check_cfuncs.lua")

Biblioteki do linkera

add_links("pthread", "m", "dl")

Aby podać ścieżki do linkera:
add_linkdirs("$(buildir)/lib")


Systemowe flagi linkera

add_syslinks("pthread")


Flagi dla linkera

add_ldflags("-static", {force = true})

Opcja
force
 jest po to, aby flaga nie została zignorowana. Na ogół o zignorowaniu flagi informuje nas xmake w formie warningu.

Flagi dla kompilatora C++

add_cxflags("-O0")


Dodatkowy kod podczas instalacji targetu

on_install("modules.test.install")

W powyższym kodzie obok pliku
xmake.lua
 potrzebujemy plik
modules/test/install.lua
, który będzie zawierał kod w lua.

Dodatkowy kod podczas/po/przed_budowaniem/instalacją/uruchamianiem

Możliwości można łączyć:
on/after/before_build/install/package/run_build/install/run


Ustawianie opcji konfiguracyjnych dla projektów

option("test1", {default = "hello", showmenu = true, description = "test1 option"})

option("test2")
    set_default(true)
    set_showmenu(true)
    set_description("test1 option")

option("test3")
    set_default(true)
    set_showmeu(true)

option("test4")
    set_default("hello")
Jest bardzo dużo możliwości (szczegóły w dokumentacji), tylko pierwszy argument opcji jest obowiązkowy, resztę można pominąć.
Opcja
showmenu
 służy do tego, żeby dana opcja była wyświetlona w menu konfiguracyjnym projektu.

Możliwość konfiguracji dla konkretnego systemu

if is_plat("linux", "macosx") then
      add_cxflags("-O0")
end
W powyższym przykładzie sprawdzamy czy mamy do czynienia z Linuxem lub MacOS, wtedy dodawana jest dodatkowa flaga

Możliwość iterowania po liście

 for _, name in ipairs({"pthread", "m", "dl"}) do
   add_links(name)
end


Wykonywanie skryptu po zakończonej kompilacji

target("Pierwszy")
    after_build(function (target)
        print("hello: %s", target:name())
        os.exec("echo %s", target:targetfile())
    end)

Dodawanie zależności do projektu (o tym później)

add_packages("tbox", "libuv", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8", "openssl")


Projekty zależne od siebie

W ramach jednego pliku
xmake.lua
 jest możliwe dodanie wielu projektów/targetów. Mamy możliwość połączyć je zależnościami:
add_deps("projekt1", "projekt2")


Łączenie projektu w archiwum

set_policy("build.merge_archive", true)


Wyłączenie użycie ccache

set_policy("build.ccache", false)

jest ono domyślnie używane.
Oczywiście można też użyć komendy zamiast zmieniać pliku konfiguracyjnego:
xmake f --ccache=n


Zmiana ustawień ostrzeżeń kompilacji (ang. warning)

Domyślnie nie są one wyświetlane, możemy je włączyć w ustawieniach:
set_policy("build.warning", true)
set_warnings("all", "extra")
a także komendą:
xmake -w


Możliwość wskazania zestawu narzędzi (ang. toolchain)

set_toolchains("llvm@llvm-10")


Możliwość tworzenia tasków

Czyli dodatkowych "komend", które można wywołać, które mogą mieć różne argumenty wykonywania. Coś na podobnym poziomie jak target, czy option. Jest to zagadnienie bardziej skomplikowane, dlatego odsyłam do dokumentacji.

Inne zależności zależne od typu projektu

Dla różnych typów projektu istnieją specjalne opcje, ułatwiające konfiguracje konkretnego typu projektu np. projektu używającego QT. Jest ich bardzo dużo, nie będę ich tutaj przytaczał.

Dodanie zależności

Załóżmy, że budujemy bibilitekę, w której potrzebujemy
#include <rapidjson/*>
, której nie mamy w ogóle w naszym systemie. Dzięki
xmake
 wystarczy zmodyfikować nasz
xmake.lua
 i wszystkie zależności zostaną automatycznie pobrane:
add_requires("rapidjson")

target("Pierwszy")
    set_kind("binary")
    add_files("src/*.cpp")

    add_packages("rapidjson")
Oczywiście po zawołaniu komendy budującej zostaniemy zapytani czy pobrać zależności. Jeśli z góry wiemy, że chcemy zainstalować wszystko można się pokusić o użycie flagi "zawsze na tak":
xmake --yes
# albo krócej:
xmake -y

Powyżej podawaliśmy zależności jako obowiązkowe, możemy ich użyć w sposób opcjonalny:
add_requires("libharu", {optional=true})


Możemy też sprecyzować wersje pakietu, a nawet alias na nazwę pakietu:
add_requires("tbox >1.6.1", {alias="tbox"})
add_requires("libuv master")

Dużym udogodnieniem jest, że można wszystkie zależności podać w jednej komendzie np.:
add_requires("tbox >1.6.1", "libuv master", "ffmpeg", "pcre2/libpcre2-8")


Instalowanie zależności przy użyciu wskazanych managerów pakietów typu vcpkg/conan/bref

Jest to możliwe, wystarczy poprzedzić nazwę zależności odpowiednią nazwą managera pakietów np.:
add_requires("vcpkg::ffmpeg", "conan::openssl/1.1.1g", "brew::pcre2/libpcre2-8")


Oczywiście te zależności należy dodać do projektu, przykładowy plik
xmake.lua
 z dokumentacji:
add_requires("tbox >1.6.1", "libuv master", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8")
add_requires("conan::openssl/1.1.1g", {alias = "openssl", optional = true, debug = true})
target("test")
     set_kind("binary")
     add_files("src/*.c")
     add_packages("tbox", "libuv", "vcpkg::ffmpeg", "brew::pcre2/libpcre2-8", "openssl")

Zależności te widać na obrazku ze strony dokumentacji xmake:

Instalowanie pakietów przy użyciu xmake

Pożądane pakiety możemy również zainstalować komendą, np.:
xrepo install zlib tbox

Alternatywnie możemy podać wersję:
xrepo install "zlib 1.2.x"
xrepo install "zlib >=1.2.0"
Ponadto mamy możliwość wybrania odpowiedniej wersji biblioteki (debug, shared):
xrepo install -m debug zlib
xrepo install -k shared zlib
Wreszcie mamy możliwość sprecyzowania konfiguracji pod pakiet:
xrepo install -f "vs_runtime='MD'" zlib
xrepo install -f "regex=true,thread=true" boost
Nie zapomnijmy też, że mamy możliwość wskazania konkretnego managera pakietów (który musi być zainstalowany w systemie):
xrepo install brew::zlib
xrepo install vcpkg::zlib
xrepo install conan::zlib/1.2.11

Olbrzymią zaletą instalacji zależności przy pomocy xrepo jest możliwość wyświetlenia flag linkowania/kompilacji:
xrepo fetch pcre2
{
  {
    linkdirs = {
      "/usr/local/Cellar/pcre2/10.33/lib"
    },
    links = {
      "pcre2-8"
    },
    defines = {
      "PCRE2_CODE_UNIT_WIDTH=8"
    },
    includedirs = "/usr/local/Cellar/pcre2/10.33/include"
  }
}
Jeśli potrzebujemy tylko jedno z tych możemy odpytać bezpośrednio:
xrepo fetch --ldflags openssl
xrepo fetch --cflags openssl
xrepo fetch --cflags --ldflags conan::zlib/1.2.11

Możliwe źródła zależności

Jest ich bardzo wiele, nawet te wbudowane w daną dystrybucję linuxa:
  • Oficjalne repozytorium xmake-repo
  • Oficjalny manager pakietów
    Xrepo
  • Manager pakietów Conan (przykład zależności:
    conan::openssl/1.1.1g
    )
  • Manager pakietów Conda (przykład zależności:
    conda::libpng 1.3.67
    )
  • Manager pakietów Vcpkg (przykład zależności:
    vcpkg:ffmpeg
    )
  • Manager pakietów Homebrew/Linuxbrew (przykład zależności:
    brew::pcre2/libpcre2-8
    )
  • Pacman dla dystrybucji archlinux/msys2 (przykład zależności:
    pacman::libcurl)
  • Apt dla dystrybucji ubuntu/debian (przykład zależności:
    apt::zlib1g-dev
    )
  • Manager pakietów języka C Clib (przykład zależności:
    clib::clibs/bytes@0.0.4
    )
  • Manager pakietów języka D https://code.dlang.org/ (przykład zależności:
    dub::log 0.4.3)
  • Portage dla dystrybucji Gentoo/Linux (przykład zależności:
    portage::libhandy
    )
  • Manager pakietów języka programowania nimlang Nimble (przykład zależności:
    nimble::zip >1.3
    )
  • Repozytoria użytkownika na github.com

Usuwanie pakietu

xmake require --uninstall tbox


Informacje o zainstalowanym pakiecie

xmake require --info tbox


Listowanie aktualnie zainstalowanych pakietów

xmake require --list


Dodanie pakietu z repozytorium github

Jest możliwe zarówno prywatne jak i publiczne repozytorium (szczegóły):
xmake repo --add myrepo git@github.com:myrepo/xmake-repo.git

Można też w pliku
xmake.lua
 dodać własne repozytoria:
add_repositories("my-repo git@github.com:myrepo/xmake-repo.git")
add_repositories("my-repo git@github.com:myrepo/xmake-repo.git dev")

Możliwość wysłania własnego pakietu do oficjalnego repozytoium

Często managery pakietów nie mają wszystkiego, na szczęście każdy może zgłosić własny pakiet. Wymaga to kilka kroków, ale jest szczegółowo opisane w oficjalnym tutorialu.

Pakiety lokalne

Czasami zależności znajdują się w repozytorium projektu, mogą to być zależności xmake'a, które są włączane w specjalny sposób (np. są w repozytorium). Szczegóły w dokumentacji.

Używanie funkcji CMake'a z wnętrza xmake'a

Twórcy xmake zdają sobie sprawę, że CMake stanowi pewien standard, dlatego udostępniają wiele funkcjonalności korzystających z tego standardu.

Możliwość znalezienia pakietu zainstalowanego w systemie przy użyciu CMake'a

xmake l find_package cmake::ZLIB


Dodawanie zależności korzystających z CMake'a

Wskazywanie komponentów:
add_requires("cmake::Boost", {system = true, configs = {components = {"regex", "system"}}))


Domyślne przełączyniki pakietów:
add_requires("cmake::Boost", {system = true, configs = {components = {"regex", "system"},
                                             presets = {Boost_USE_STATIC_LIB = true}}})

Zmienne środowiskowe:
add_requires("cmake::OpenCV", {system = true, configs = {envs = {CMAKE_PREFIX_PATH = "xxx"}}})


Możliwość używania pakietów z xmake'a w CMake'u

Sprowadza się do tego, że instalujemy odpowiedni pakiet do CMake'a, przy pomocy którego ładujemy zależności do pliku CMake. Jest to opisane w oficjalnym tutorialu.

Inne możliwości xmake'a


Tryb cichy logowania

xmake --quiet
# alternatywnie:
xmake -q

Tryb wylewny logowania (ang. verbose)

xmake --verbose
# alternatywnie:
xmake -v

Środowisko izolowane

W temacie zależności - możliwe jest utworzenie wirtualnego środowiska izolowanego dla zależności (jak python venv):
xrepo env shell
.
Aby wyjść ze środowiska izolowanego:
xrepo env quit
.

Generowanie konkurencyjnych plików konfigracyjnych dla projektów

Xmake wspiera również generowanie m.in. CMake, Ninja, komendy kompilacji, VisualStudio z projektu używającego xmake'u:
  • xmake project -k makefile
  • xmake project -k cmakelists
  • xmake project -k ninja
  • xmake project -k compiler_flags
  • xmake project -k xcode
  • xmake project -k vsxmake -m "debug;release"
     alternatywnie można podać wersję:
    xmake project -k [vsxmake2010|vsxmake2013|vsxmake2015|..] -m "debug;release"

Integracja z IDE

Narzędzie
xmake
 posiada wtyczki dla popularnych środowisk programistycznych:
  • VS Code
  • Sublime
  • Idea
  • nvim
  • vim
  • visualstudio
  • qtcreator

Wykrywanie ustawień systemu i architektury

Zaletą CMake'a jest możliwość sprawdzenia nie tylko zależności, ale również m.in. typów, nagłówków, czy funkcjonalności kompilatora itp.
xmake
 również ma taką możliwość, po włączeniu odpowiedniego modułu np.
includes("check_ctypes.lua")

target("test")
    set_kind("binary")
    add_files("*.c")
    add_configfiles("config.h.in")
    configvar_check_ctypes("HAS_WCHAR", "wchar_t")
    configvar_check_ctypes("HAS_WCHAR_AND_FLOAT", {"wchar_t", "float"})
    configvar_check_cincludes("HAS_STRING_H", "string.h")
    configvar_check_cincludes("HAS_STRING_AND_STDIO_H", {"string.h", "stdio.h"})
    configvar_check_csnippets("HAS_STATIC_ASSERT", "_Static_assert(1, \"\");")
    configvar_check_csnippets("HAS_LONG_8", "return (sizeof(long) == 8)? 0: -1;", {tryrun = true})
    configvar_check_features("HAS_CONSEXPR_AND_STATIC_ASSERT", {"cxx_constexpr", "c_static_assert"}, {languages = "c++11"})
Więcej informacji na stronie dokumentacji.

Rodzaje targetów

Czyli to co ustawiamy przez komendę
set_kind("...")
 (więcej szczegółów):
  • binary
     - program binarny (wykonywalny)
  • static
    - biblioteka statyczna
  • shared
    - biblioteka dynamiczna
  • object
    - skompilowana kolekcja obiektów
  • headeronly
    - kolekcja nagłówków
  • phony
    - jest to pusty target, służy do wskazania zależności między targetami

Zdalne, rozproszone budowanie, unity building

Narzędzie jest wyposażone też w funkcje: zdalnnego budowania, rozproszonego budowania, unity building.

Generowanie dokumentacji doxygen

W tym celu wystarczy zawołać:
xmake doxygen


Różne style graficzne

Ciekawostką jest możliwość zmiany szablonów działania w konsoli narzędzia
xmake
:
xmake g --theme=ninja $ źródło: https://www.youtube.com/watch?v=Z1YsG3TpuS0
xmake g --theme=emoji
xmake g --theme=dark
xmake g --theme=light
xmake g --theme=plain
xmake g --theme=powershell
xmake g --theme=default # alternatywnie: xmake g -c

Pozostałe ustawienia

Jest też bardzo dużo innych, mniej popularnych ustawień np. tworzenie własnych reguł dla plików o określonych rozszerzeniach, ustawienie zestawów narzędzi (ang. toolchain), ustawienia pakietów i zależności między nimi. Poza tym również jest możliwe pobieranie informacji o pakietach, targetach, opcjach, modułach wbudowanych i rozszerzeniach modułów.

Płatne wsparcie

Narzędzie xmake jest bezpłatne, natomiast można skorzystać z płatnego wsparcia.

API ściąga (ang. cheetsheet)

Czyli nazwy niewymienione wcześniej, które mogą się przydać.

Wbudowane predykaty

Czyli funkcje zwracające prawdę lub fałsz, na których podstawie można dokonać ustawień warunkowych, przykładowo:
funkcja opis przykłady
is_os
czy aktualnym systemem jest ten podany w argumencie (można podać wiele systemów) windows, linux, android, macosx, ios
is_arch
czy aktualna architektura jest jedną z tych podanych w argumencie x86_64, i386
is_plat
czy aktualnie mamy podaną platformę windows, linux, macosx, android, iphoneos, watchos
is_host
czy kompilacja odbywa się na danym systemie windows, linux, macosx
is_subhost
czy budujemy na podsystemie msys, cygwin
is_subarch
czy budujemy na podarchitekturę (dotyczy to msys i cygwin)
is_mode
czy jest to podany tryb kompilacji debug, release, profile
is_kind
czy jest używany podany tryb targetu static, shared
is_config
czy ustawiono daną opcje konfiguracyjną.
Przykładowo opcję
test
 ustawiamy tak:
xmake f --test=hello1
has_config
jw. z tymże wprowadzona w wersji 2.2
xmake'a
has_package
czy dany pakiet jest dostępny tbox

Funkcje ustawiające projekt

Poniżej jest opis wybranych funkcji globalnych ustawiających projekt (całość w dokumentacji):
set_project("...")
ustawienie nazwy projektu
set_version("1.0.1")
ustawienie wersji projektu, możliwe argumenty opcjonalne:
{build = "%Y%m%d%H%M", soname}
set_xmakever("2.1.0")
 
ustawienie minimalnej wersji xmake
add_moduledirs("$(projectdir)/modules")
dodanie ścieżki z własnymi modułami
if get_config("myconfig") == "xxx" then
    add_defines("HELLO")
end
pobranie konfiguracji
set_config("name", "value")
ustawienie domyślnej konfiguracji, którą można zmienić przy użyciu komendy:
xmake f --name=value

Dodatkowe ustawienia targetu

Robimy to pod targetem, czyli:
target("demo")
    -- tutaj ustawiamy
Poniżej wymieniłem wybrane ustawienia (pełna lista znajduje się w dokumentacji, ustawień tych jest bardzo dużo):
set_strip("...")
przycinanie dymboli debugowych np.
set_strip("all")
set_default(true)
domyślny target (czyli budowany gdy nie sprecyzujemy inaczej)
set_basename("xxx_$(mode)_$(arch)")
ustawienie domyślnej nazwy pliku wynikowego, do niej zostaną dodane rozszerzenia czy prefixy
set_filename("")
ustawia nazwę, do której nie są dodawane prefixy ani suffixy (rozszerzenia)
set_extension("exe")
ustawienie rozszerzenia
set_warnings("...")
ustawia różne poziomy warningów, np. set_warnings("all", "error") odpowiada
-Wall -Wextra -Weffc++ / -Weverything
 i
-Werror
 (wszystkie możliwości)
set_optimize()
optymalizacja kompilatora np.
set_optimize("fastest")
, (wszystkie możliwości)
set_languages("cxx20", "c17")
ustawienie standardu kompilatora dla różnych języków, w tym wypadku C++20 i C17
set_targetdir("/tmp/build")
ustawienie katalog wynikowy zbudowanego targetu
add_rules()
możliwość utworzenia reguły obsługi plików o danym rozszerzeniu np. dla nieobsługiwanych języków programowania (więcej informacji)
on_clean(...)
ustawienie funkcji wołanej podczas czyszczenia np.
target("test")
    on_clean(function (target)
        os.rm(target:targetfile())
    end)
set_pcxxheader("header.h")
ustawienie nagłówka jako prekompilowany
remove_files("src/test.c")
możliwość usunięcia pliku z plików z których powstaje target (przydatne gdy używamy np.
add_files("src/*.c")
)
add_rpathdirs()
ustawienie ścieżki RPath
add_cflags
dodanie dodatkowych flag kompilatora C
add_cxflags
dodanie dodatkowych flag kompilatorów C i C++
add_cxxflags
dodanie dodatkowych flag kompilatora C++
add_ldflags
dodanie flag linkera
set_toolset("cc", "$(projectdir)/tools/bin/clang-5.0")
ustawienie zestawu narzędzi, co może być przydatne gdy w projekcie zawieramy np. własny kompilator
set_rundir("$(projectdir)/xxx")
ustawienie ścieżki wykonywania programu
add_runenvs("PATH", "/tmp/bin", "xxx/bin")
ustawienie zmiennych środowiskowych wykonywanego programu
set_encodings("utf-8")
ustawienie kodowania plików źródłowych i docelowych (możliwe jest tylko źródłowych lub tylko docelowych)
add_forceincludes("config.h")
dodanie nagłówka podczas kompilacji bez ręcznego dodawania go w kodzie
add_extrafiles("assets/other.txt")
dodanie pliku, który nie jest kodem, do projektu
add_tests(...)
umożliwia dodanie testów, użycie tej komendy jest bardziej skomplikowane, dlatego odsyłam do dokumentacji

Dla ułatwienia kolejność wywołania funkcji przy budowaniu targetu:
on_load
 ->
after_load
 ->
on_config
 ->
before_build
 ->
on_build
 ->
after_build
 ->
on_link

Mamy też:
before_run
 ->
on_run
 ->
after_run


Wbudowane zmienne

$(os)
aktualny system operacyjny
$(host)
natywny system operacyjny
$(tmpdir)
katalog tymczasowy
$(curdir)
aktualna ścieżka
$(buildir)
katalog do budowania
$(scriptdir)
katalog aktualnego skryptu, gdzie jest plik
xmake.lua
$(globaldir)
katalog z globalnymi ustawieniami, domyślnie dla linuxa jest to
~/.config
$(configdir)
katalog konfiguracyjny projektu
$(programdir)
katalog instalacyjny skryptów xmake'a
$(projectdir)
katalog główny projektu (ang. root directory)
$(shell)
wykonywalna komenda powłoki np.
target("test")
    set_kind("binary")
    if is_plat("linux") then
        add_ldflags("$(shell pkg-config --libs sqlite3)")
    end
$(env)
zmienne środowiskowe
$(reg)
wartość konfiguracyjna rejestru windows
Poza zmiennymi wbudowanymi można w łatwy sposób tworzyć własne:
xmake f --var=val

taką zmienną odczytujemy w następujący sposób:
target("test")
    add_defines("-DTEST=$(var)")

Bibliografia


Autorzy artykułu

Autor Zakres zmian Afiliacja
Bazior Grzegorz Utworzenie artykułu Pracownik AGH w Krakowie