Xmakeは、Lua に基づく軽量のクロスプラットフォーム ビルド ユーティリティです。
Lua ランタイムが組み込まれているため、非常に軽量で依存関係がありません。
プロジェクトのビルドを維持するために xmake.lua を使用し、その構成構文は非常にシンプルで読みやすいです。
これを使用して、Make/Ninja のようにプロジェクトを直接ビルドしたり、CMake/Meson のようにプロジェクト ファイルを生成したりできます。また、ユーザーが C/C++ 依存ライブラリの統合使用を解決するのに役立つ組み込みのパッケージ管理システムも備えています。
Xmake = Build backend + Project Generator + Package Manager + [Remote|Distributed] Build + Cache
あまり正確ではありませんが、Xmake は次のように理解できます。
Xmake ~= Make/Ninja + CMake/Meson + Vcpkg/Conan + distcc + ccache/sccache
ギットハブ
書類
新機能の紹介
パッケージ コンポーネントのサポート
序章
この新機能は、C/C++ パッケージから特定のサブライブラリを統合できるようにすることを目的としており、通常、大規模なパッケージでのライブラリ コンポーネントの統合に使用されます。
これは、そのようなパッケージが多数のサブライブラリを提供するためであり、それらのすべてがユーザーに必要なわけではなく、それらすべてをリンクすると問題が発生する可能性があります。
ただし、以前のバージョンでは、サブライブラリ選択の機能をサポートできました。
add_requires("sfml~foo", {configs = {graphics = true, window = true}})
add_requires("sfml~bar", {configs = {network = true}})
target("foo")
set_kind("binary")
add_packages("sfml~foo")
target("bar")
set_kind("binary")
add_packages("sfml~bar")
これは、各パッケージのカスタム構成によって行われますが、このアプローチにはいくつかの問題があります。
sfml~foosfml~bar2 つの個別のパッケージとして繰り返しインストールされ、2 倍のディスク容量を占有します。
一部の共通コードは繰り返しコンパイルされ、インストールの効率に影響します。
sfml~fooターゲットが と の両方に依存している場合、sfml~barリンクの競合が発生します。
二重コンパイルとディスク使用量の影響は、boost などの非常に大規模なパッケージ統合の場合に非常に高くなる可能性があり、サブライブラリの組み合わせが多数ある場合は、ディスク使用量が N 倍を超えることさえあります。
この問題を解決するために、Xmake にはパッケージ コンポーネント モードが追加されました。これにより、次の利点がいくつか提供されます。
1 回のコンパイルで任意の数のコンポーネントを迅速に統合し、インストール効率を大幅に向上させ、ディスク フットプリントを削減します。
コンパイラとプラットフォーム全体でのコンポーネントの抽象化により、ユーザーは各サブライブラリ間のリンク順序の依存関係の構成について心配する必要がなくなります
より使いやすく
背景の詳細については、#2636を参照してください。
パッケージ コンポーネントを使用する
ユーザーにとって、パッケージコンポーネントの使用は非常に便利です。パッケージが使用されている限り、ユーザーはパッケージを維持する必要がないため、パッケージは関連するコンポーネントのセットで構成されており、すぐに統合して使用することができます。
add_requires("sfml")
target("foo")
set_kind("binary")
add_packages("sfml", {components = "graphics"})
target("bar")
set_kind("binary")
add_packages("sfml", {components = "network"})
パッケージのコンポーネントを表示
では、特定のパッケージが提供するコンポーネントをどのように知るのでしょうか? 次のコマンドを実行して確認できます。
$ xrepo info sfml
The package info of project:
require(sfml):
-> description: Simple and Fast Multimedia Library
-> version: 2.5.1
...
-> components:
-> system:
-> graphics: system, window
-> window: system
-> audio: system
-> network: system
パッケージ コンポーネントの構成
あなたがパッケージのメンテナーであり、パッケージにコンポーネント サポートを追加したい場合は、次の 2 つのインターフェイスを介してパッケージ コンポーネントを構成する必要があります。
add_components: パッケージ コンポーネントのリストを追加します
on_component: 各パッケージ コンポーネントを構成します
パッケージ コンポーネントのリンク構成
ほとんどの場合、パッケージ コンポーネントは、独自のサブリンク情報の一部で構成するだけで済みます。
package("sfml")
add_components("graphics")
add_components("audio", "network", "window")
add_components("system")
on_component("graphics", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-graphics" ... e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("links", "freetype")
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
end)
on_component("window", function (package, component)
local e = package:config("shared") and "" or "-s"
component:add("links", "sfml-window" ... e)
if package:is_plat("windows", "mingw") and not package:config("shared") then
component:add("syslinks", "opengl32", "gdi32", "user32", "advapi32")
end
end)
...
上記は不完全なパッケージ構成です。パッケージ コンポーネントに関連する構成の一部のみを抽出しました。
パッケージ コンポーネントの構成と使用の完全な例は、コンポーネントの例で見つけることができます。
コンポーネントのコンパイル情報を構成する
各コンポーネントのリンク情報だけでなく、includedirs、定義などのコンパイル情報も構成できます。各コンポーネントを個別に構成することもできます。
package("sfml")
on_component("graphics", function (package, component)
package:add("defines", "TEST")
end)
コンポーネントの依存関係を構成する
package("sfml")
add_components("graphics")
add_components("audio", "network", "window")
add_components("system")
on_component("graphics", function (package, component)
component:add("deps", "window", "system")
end)
window上記の構成は、グラフィックス コンポーネントがおよびコンポーネントに追加の依存関係を持つことをパッケージに伝えsystemます。
したがって、ユーザー側では、グラフィック コンポーネントの使用は、
add_packages("sfml", {components = {"graphics", "window", "system"})
に簡略化
add_packages("sfml", {components = "graphics")
グラフィックス コンポーネントをオンにするとすぐに、依存するウィンドウとシステム コンポーネントも自動的に有効になり、リンクが正しい順序であることが自動的に確認されるためです。
または、コンポーネントの依存関係を で構成できますadd_components("graphics", {deps = {"window", "system"}})。
システム ライブラリからコンポーネントを検索する
add_extsourcesパッケージ構成で構成すると、たとえば apt/pacman などのシステム パッケージ マネージャーからライブラリを見つけることで、システムでのパッケージ検出が改善されることがわかっています。
もちろん、各コンポーネントがextsources構成を介してシステム リポジトリからそれらを優先的に検索できるようにすることもできます。
たとえば、実際には自作でもコンポーネント化されている sfml パッケージは、毎回ソースにインストールすることなく、システム リポジトリから各コンポーネントを検索するように作成できます。
$ ls -l /usr/local/opt/sfml/lib/pkgconfig
-r--r--r-- 1 ruki admin 317 10 19 17:52 sfml-all.pc
-r--r--r-- 1 ruki admin 534 10 19 17:52 sfml-audio.pc
-r--r--r-- 1 ruki admin 609 10 19 17:52 sfml-graphics.pc
-r--r--r-- 1 ruki admin 327 10 19 17:52 sfml-network.pc
-r--r--r-- 1 ruki admin 302 10 19 17:52 sfml-system.pc
-r--r--r-- 1 ruki admin 562 10 19 17:52 sfml-window.pc
コンポーネントごとに、その extsources を構成する必要があるだけです。
if is_plat("macosx") then
add_extsources("brew::sfml/sfml-all")
end
on_component("graphics", function (package, component)
-- ...
component:add("extsources", "brew::sfml/sfml-graphics")
end)
デフォルトのグローバル コンポーネント構成
コンポーネント名を指定して特定のコンポーネントを構成することに加えて、コンポーネント名を指定しない場合、デフォルトではすべてのコンポーネントをグローバルに構成します。
package("sfml")
on_component(function (package, component)
-- configure all components
end)
もちろん、グラフィック コンポーネントの構成を指定することもできます。残りのコンポーネントは、デフォルトのグローバル構成インターフェイスを介して次のように構成されます。
package("sfml")
add_components("graphics")
add_components("audio", "network", "window")
add_components("system")
on_component("graphics", function (package, component)
-- configure graphics
end)
on_component(function (package, component)
-- component audio, network, window, system
end)
C++ モジュールのビルドの改善
インクリメンタル ビルドのサポート
Xmake はすでに C++ モジュールを適切にサポートしていると思っていましたが、そのインクリメンタル ビルドがまだ適切に機能していないことに気付きました。
そのため、このバージョンの Xmake は、C++ モジュールのインクリメンタル ビルドのサポートも適切に行っていますが、サポート プロセスには依然として多くの労力が必要でした。
私の分析によると、*.dモジュールで生成されるインクルード依存関係情報 ( ) の形式は、コンパイラーによってかなり異なります。
gcc 形式は最も複雑ですが、とにかくサポートするようにしました。
build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o: src/foo.mpp
build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o gcm.cache/foo.gcm: bar.c++m cat.c++m
foo.c++m: gcm.cache/foo.gcm
.PHONY: foo.c++m
gcm.cache/foo.gcm:| build/.objs/dependence/linux/x86_64/release/src/foo.mpp.o
CXX_IMPORTS += bar.c++m cat.c++m
clang はフォーマットの互換性が最も優れており、特別な変更を加えることなくサポートします。
build//hello.pcm: /usr/lib/llvm-15/lib/clang/15.0.2/include/module.modulemap src/hello.mpp
msvc 形式は、より拡張性が高く、解析とサポートが容易です。
{
"Version": "1.2",
"Data": {
"Source": "c:\users\ruki\desktop\user_headerunit\src\main.cpp",
"ProvidedModule": "",
"Includes": [],
"ImportedModules": [
{
"Name": "hello",
"BMI": "c:\users\ruki\desktop\user_headerunit\src\hello.ifc"
}
],
"ImportedHeaderUnits": [
{
"Header": "c:\users\ruki\desktop\user_headerunit\src\header.hpp",
"BMI": "c:\users\ruki\desktop\user_headerunit\src\header.hpp.ifc"
}
]
}
}
循環依存検出のサポート
モジュール間には依存関係があるため、複数のモジュール間に循環依存関係があるとコンパイルできません。
ただし、以前のバージョンでは、Xmake はこれを検出できず、循環依存関係が発生した場合、コンパイルはメッセージなしで停止し、ユーザーにとって非常に不親切でした。
この新しいバージョンでは、モジュールの循環依存の検出を追加することでこの状況を改善し、コンパイル時に次のエラー メッセージが表示され、ユーザーが問題を見つけやすくなります。
$ xmake
[ 0%]: generating.cxx.module.deps Foo.mpp
[ 0%]: generating.cxx.module.deps Foo2.mpp
[ 0%]: generating.cxx.module.deps Foo3.mpp
[ 0%]: generating.cxx.module.deps main.cpp
error: circular modules dependency(Foo2, Foo, Foo3, Foo2) detected!
-> module(Foo2) in Foo2.mpp
-> module(Foo) in Foo.mpp
-> module(Foo3) in Foo3.mpp
-> module(Foo2) in Foo2.mpp
より LSP に適した構文形式
ドメイン構成構文のデフォルトの規則は、非常にきれいですが、自動フォーマットされたインデントと IDE にはあまり適していません。また、構成をフォーマットすると、インデントが完全に間違った場所に配置されます。
target("foo")
set_kind("binary")
add_files("src/*.cpp")
また、2 つのターゲット間で何らかのグローバル構成が構成されている場合、現在のターゲット スコープは自動的に終了せず、ユーザーは明示的に ``target_end()` を呼び出す必要があります。
target("foo")
set_kind("binary")
add_files("src/*.cpp")
target_end()
add_defines("ROOT")
target("bar")
set_kind("binary")
add_files("src/*.cpp")
上で述べたように、do endモードを使用して自動インデントの問題を解決できますが、必要性の問題はtarget_end()依然として存在します。
target("foo") do
set_kind("binary")
add_files("src/*.cpp")
end
target_end()
add_defines("ROOT")
target("bar") do
set_kind("binary")
add_files("src/*.cpp")
end
したがって、この新しいバージョンでは、自動インデント、ターゲット ドメインの分離の問題を解決するために、より優れたオプションのドメイン構成構文を提供します。
target("foo", function ()
set_kind("binary")
add_files("src/*.cpp")
end)
add_defines("ROOT")
target("bar", function ()
set_kind("binary")
add_files("src/*.cpp")
end)
foo フィールドと bar フィールドは完全に分離されているため、それらに影響を与えずにそれらの間で他の設定を構成できます。また、LSP との親和性が非常に高く、ワンクリックの書式設定でもインデントの混乱を引き起こすことはありません。
注: これはオプションの拡張構文にすぎません。既存の構成構文は引き続き完全にサポートされており、ユーザーは必要に応じて適切なものを選択できます。
特定のコンパイラにフラグを追加する
add_cflags、などのインターフェイスを使用して構成された値add_cxxflagsは、通常、コンパイラ固有ですが、Xmake は自動検出およびマッピング メカニズムを提供します。現在のコンパイラでサポートされていないフラグが設定されている場合でも、Xmake はそれを自動的に無視できますが、それでも警告が表示されます。
この新しいバージョンでは、すべてのフラグを追加するためのインターフェイスを改善し、特定のコンパイラに対してのみフラグを指定することで追加の警告を回避しました。
add_cxxflags("clang::-stdlib=libc++")
add_cxxflags("gcc::-stdlib=libc++")
または
add_cxxflags("-stdlib=libc++", {tools = "clang"})
add_cxxflags("-stdlib=libc++", {tools = "gcc"})
注: コンパイル フラグだけでなく、add_ldflags などのリンク フラグも機能します。
renderdoc デバッガーのサポート
Xmake が renderdoc を直接読み込んで一部のグラフィック レンダラーをデバッグできるようにするこの優れた機能に貢献してくれた@SirLynixに感謝します。
使い方はとても簡単です。最初に renderdoc がインストールされていることを確認してから、次のようにデバッガを renderdoc に設定し、デバッグ実行をロードします。
$ xmake f --debugger=renderdoc
$ xmake run -d
具体的な使用効果は以下の通りです。
新しい C++ 例外インターフェイスの構成
Xmake は、新しいset_exceptions抽象化構成インターフェイスを追加しました。これにより、C++/Objc 例外を有効または無効に構成できます。
通常、 add_cxxflags インターフェースを介してそれらを構成すると、プラットフォームに応じてコンパイラーがそれらを個別に処理するのは面倒になります。
例えば
on_config(function (target)
if (target:has_tool("cxx", "cl")) then
target:add("cxflags", "/EHsc", {force = true})
target:add("defines", "_HAS_EXCEPTIONS=1", {force = true})
elseif(target:has_tool("cxx", "clang") or target:has_tool("cxx", "clang-cl")) then
target:add("cxflags", "-fexceptions", {force = true})
target:add("cxflags", "-fcxx-exceptions", {force = true})
end
end)
そして、このインターフェイスを使用すると、コンパイラに依存しない方法でそれらを抽象化して構成できます。
C++ 例外の有効化:
set_exceptions("cxx")
C++ 例外を無効にします。
set_exceptions("no-cxx")
同時に objc 例外を有効にするように構成することもできます。
set_exceptions("cxx", "objc")
またはそれらを無効にします。
set_exceptions("no-cxx", "no-objc")
Xmake は、フラグを内部的にさまざまなコンパイラに自動的に適合させます。
ispc コンパイル規則のサポート
Xmake は、次のように使用される@star-hengxing のおかげで、ipsc コンパイラの組み込みルールのサポートを追加しました。
target("test")
set_kind("binary")
add_rules("utils.ispc", {header_extension = "_ispc.h"})
set_values("ispc.flags", "--target=host")
add_files("src/.ispc")
add_files("src/.cpp")
msvc の armasm コンパイラのサポート
Xmake の以前のバージョンでは、Windows ARM の初期サポートが追加されましたが、asm コンパイルはまだ適切にサポートされていなかったため、このバージョンでは Windows ARM サポートを引き続き改善しています。
msvc のサポートが利用可能armasm.exeになりarmasm64.exeました。
さらに、Windows ARM プラットフォームのパッケージ クロス コンパイル サポートも改善されました。
新しい gnu-rm ビルド規則
Xmake は、 @JacobPengのおかげで、gnu-rm ツールチェーンを使用して組み込みプロジェクトを構築するための新しいルールとサンプル プロジェクトも追加しました。
add_rules("mode.debug", "mode.release")
add_requires("gnu-rm")
set_toolchains("@gnu-rm")
set_plat("cross")
set_arch("armv7")
target("foo")
add_rules("gnu-rm.static")
add_files("src/foo/*.c")
target("hello")
add_deps("foo")
add_rules("gnu-rm.binary")
add_files("src/.c", "src/.S")
add_files("src/*.ld")
add_includedirs("src/lib/cmsis")
完全なプロジェクトについては、Embed GNU-RM の例を参照してください。
OpenBSD システムのサポートを追加
以前のバージョンでは、Xmake は FreeBSD のみをサポートしていました。OpenBSD には、Xmake のコンパイルとインストールを妨げる多くの違いがありました。
新しいバージョンは、OpenBSD での Xmake の実行を完全にサポートするようになりました。
変更ログ
新機能
新しいオプションの構成構文。これは LSP フレンドリーで、自動的に target_end() を呼び出してスコープの分離を実現します。
#2944gnu-rm.binary : 埋め込みプロジェクトのルールとgnu-rm.staticテストを追加
#2636 : パッケージコンポーネントのサポート
msvc の armasm/armasm64 をサポート
#3023 : renderdoc によるデバッグのサポートを追加
#3022 : 特定のコンパイラとリンカーのフラグを追加
#3025 : C++ 例外の有効/無効切り替えメソッド
#3017 : ispc コンパイラをサポート
変更点
#2925 : doxygen プラグインの改善
#2948 : OpenBSD に対応
xmake g --insecure-ssl=yパッケージのダウンロード時に SSL 証明書を無効にするオプションを追加
#2971 : vs および vsxmake プロジェクト生成の安定化
#3000 : モジュールのインクリメンタル コンパイル サポート
#3016 : clang/msvc を改善して std モジュールをより適切にサポート
バグ修正
#2949 : 修正 vs グループ
#2952 : 長い引数の armlink を修正
#2954 : C++ モジュールのパーティション パスの問題を修正
#3033 : 循環モジュールの依存関係を検出