How to use xpm
This section is intended for those who plan to integrate xpm into their workflows.
Use existing xpm enabled projects
For projects that already include the xpm metadata, at its most basic level, the xpm workflow involves two key tasks:
- Installing dependencies
- Running various actions related to significant development steps
The easiest way to experiment with this is to use an existing project. For instance, you can start with a simple C project that prints the traditional Hello, World! message.
The first step is to clone the project into a temporary folder of your choice:
git clone https://github.com/xpack/xpm-demo-hello1.git
Install dependencies
The next major step in the workflow is to satisfy the project dependencies. In this example, xpm will install clang, since it is more portable than gcc.
cd xpm-demo-hello1
xpm install
It should be noted that this command will not install just any version of clang, but a specific version (18.1.8 in this case), which is hard-coded into the project metadata. This ensures that the same version is used across all platforms, enhancing reproducibility.
Run actions
The next steps involve running several actions, beginning with one that prepares the build folder:
xpm run prepare
The next action is to build the executable:
xpm run build
The final action is to execute the program:
xpm run execute
As expected, the result is:
Hello World!
It should be noted that all these commands work the same on all major platforms (Windows, macOS, and GNU/Linux).
Create new projects
As it can be seen, the workflow for existing projects is trivial.
However, for a better understanding, it is useful to also know how to create an xpm enabled project from scratch.
Initialise project
Similarly to npm, a project must be prepared for xpm use.
Run the following commands in a temporary folder of your choice:
mkdir xpm-demo-hello && cd xpm-demo-hello
xpm init
This adds an empty package.json
where further definitions will be stored.
Add source code
Add a simple C program that prints the traditional Hello World! message:
#include <stdio.h>
int
main (int argc, char* argv[])
{
printf ("Hello World!\n");
return 0;
}
Install a toolchain
To compile this C program, we'll use clang 18.
To install it, use the following command:
xpm install @xpack-dev-tools/clang@18.1.8-2.1
LLVM/clang is prefered over GCC since it proved to be more portable. For the moment GCC on macOS is not very stable over multiple SDK releases, and therefore not recommended.
This command will add the following links to the project:
% tree -a -L2 xpacks
xpacks
├── .bin
│ ├── analyze-build -> ../@xpack-dev-tools/clang/.content/bin/analyze-build
│ ├── clang -> ../@xpack-dev-tools/clang/.content/bin/clang
│ ├── clang++ -> ../@xpack-dev-tools/clang/.content/bin/clang++
│ ├── clang-check -> ../@xpack-dev-tools/clang/.content/bin/clang-check
│ ├── clang-cl -> ../@xpack-dev-tools/clang/.content/bin/clang-cl
│ ├── clang-cpp -> ../@xpack-dev-tools/clang/.content/bin/clang-cpp
│ ├── clang-doc -> ../@xpack-dev-tools/clang/.content/bin/clang-doc
│ ├── clang-format -> ../@xpack-dev-tools/clang/.content/bin/clang-format
│ ├── clang-include-cleaner -> ../@xpack-dev-tools/clang/.content/bin/clang-include-cleaner
│ ├── clang-linker-wrapper -> ../@xpack-dev-tools/clang/.content/bin/clang-linker-wrapper
│ ├── clang-refactor -> ../@xpack-dev-tools/clang/.content/bin/clang-refactor
│ ├── clang-rename -> ../@xpack-dev-tools/clang/.content/bin/clang-rename
│ ├── clang-repl -> ../@xpack-dev-tools/clang/.content/bin/clang-repl
│ ├── clang-scan-deps -> ../@xpack-dev-tools/clang/.content/bin/clang-scan-deps
│ ├── clang-tblgen -> ../@xpack-dev-tools/clang/.content/bin/clang-tblgen
│ ├── clang-tidy -> ../@xpack-dev-tools/clang/.content/bin/clang-tidy
│ ├── clangd -> ../@xpack-dev-tools/clang/.content/bin/clangd
│ ├── darwin-debug -> ../@xpack-dev-tools/clang/.content/bin/darwin-debug
│ ├── diagtool -> ../@xpack-dev-tools/clang/.content/bin/diagtool
│ ├── git-clang-format -> ../@xpack-dev-tools/clang/.content/bin/git-clang-format
│ ├── hmaptool -> ../@xpack-dev-tools/clang/.content/bin/hmaptool
│ ├── ld.lld -> ../@xpack-dev-tools/clang/.content/bin/ld.lld
│ ├── ld64.lld -> ../@xpack-dev-tools/clang/.content/bin/ld64.lld
│ ├── llc -> ../@xpack-dev-tools/clang/.content/bin/llc
│ ├── lld -> ../@xpack-dev-tools/clang/.content/bin/lld
│ ├── lld-link -> ../@xpack-dev-tools/clang/.content/bin/lld-link
│ ├── lldb -> ../@xpack-dev-tools/clang/.content/bin/lldb
│ ├── lldb-argdumper -> ../@xpack-dev-tools/clang/.content/bin/lldb-argdumper
│ ├── lldb-instr -> ../@xpack-dev-tools/clang/.content/bin/lldb-instr
│ ├── lldb-server -> ../@xpack-dev-tools/clang/.content/bin/lldb-server
│ ├── lli -> ../@xpack-dev-tools/clang/.content/bin/lli
│ ├── llvm-addr2line -> ../@xpack-dev-tools/clang/.content/bin/llvm-addr2line
│ ├── llvm-ar -> ../@xpack-dev-tools/clang/.content/bin/llvm-ar
│ ├── llvm-as -> ../@xpack-dev-tools/clang/.content/bin/llvm-as
│ ├── llvm-bitcode-strip -> ../@xpack-dev-tools/clang/.content/bin/llvm-bitcode-strip
│ ├── llvm-config -> ../@xpack-dev-tools/clang/.content/bin/llvm-config
│ ├── llvm-cov -> ../@xpack-dev-tools/clang/.content/bin/llvm-cov
│ ├── llvm-cxxdump -> ../@xpack-dev-tools/clang/.content/bin/llvm-cxxdump
│ ├── llvm-cxxfilt -> ../@xpack-dev-tools/clang/.content/bin/llvm-cxxfilt
│ ├── llvm-cxxmap -> ../@xpack-dev-tools/clang/.content/bin/llvm-cxxmap
│ ├── llvm-debuginfo-analyzer -> ../@xpack-dev-tools/clang/.content/bin/llvm-debuginfo-analyzer
│ ├── llvm-debuginfod -> ../@xpack-dev-tools/clang/.content/bin/llvm-debuginfod
│ ├── llvm-debuginfod-find -> ../@xpack-dev-tools/clang/.content/bin/llvm-debuginfod-find
│ ├── llvm-diff -> ../@xpack-dev-tools/clang/.content/bin/llvm-diff
│ ├── llvm-dis -> ../@xpack-dev-tools/clang/.content/bin/llvm-dis
│ ├── llvm-dlltool -> ../@xpack-dev-tools/clang/.content/bin/llvm-dlltool
│ ├── llvm-dwarfutil -> ../@xpack-dev-tools/clang/.content/bin/llvm-dwarfutil
│ ├── llvm-lib -> ../@xpack-dev-tools/clang/.content/bin/llvm-lib
│ ├── llvm-libtool-darwin -> ../@xpack-dev-tools/clang/.content/bin/llvm-libtool-darwin
│ ├── llvm-nm -> ../@xpack-dev-tools/clang/.content/bin/llvm-nm
│ ├── llvm-objcopy -> ../@xpack-dev-tools/clang/.content/bin/llvm-objcopy
│ ├── llvm-objdump -> ../@xpack-dev-tools/clang/.content/bin/llvm-objdump
│ ├── llvm-otool -> ../@xpack-dev-tools/clang/.content/bin/llvm-otool
│ ├── llvm-profdata -> ../@xpack-dev-tools/clang/.content/bin/llvm-profdata
│ ├── llvm-ranlib -> ../@xpack-dev-tools/clang/.content/bin/llvm-ranlib
│ ├── llvm-rc -> ../@xpack-dev-tools/clang/.content/bin/llvm-rc
│ ├── llvm-readelf -> ../@xpack-dev-tools/clang/.content/bin/llvm-readelf
│ ├── llvm-readobj -> ../@xpack-dev-tools/clang/.content/bin/llvm-readobj
│ ├── llvm-remarkutil -> ../@xpack-dev-tools/clang/.content/bin/llvm-remarkutil
│ ├── llvm-sim -> ../@xpack-dev-tools/clang/.content/bin/llvm-sim
│ ├── llvm-size -> ../@xpack-dev-tools/clang/.content/bin/llvm-size
│ ├── llvm-strings -> ../@xpack-dev-tools/clang/.content/bin/llvm-strings
│ ├── llvm-strip -> ../@xpack-dev-tools/clang/.content/bin/llvm-strip
│ ├── llvm-symbolizer -> ../@xpack-dev-tools/clang/.content/bin/llvm-symbolizer
│ ├── llvm-tblgen -> ../@xpack-dev-tools/clang/.content/bin/llvm-tblgen
│ ├── llvm-tli-checker -> ../@xpack-dev-tools/clang/.content/bin/llvm-tli-checker
│ ├── llvm-windres -> ../@xpack-dev-tools/clang/.content/bin/llvm-windres
│ ├── run-clang-tidy -> ../@xpack-dev-tools/clang/.content/bin/run-clang-tidy
│ ├── scan-build-py -> ../@xpack-dev-tools/clang/.content/bin/scan-build-py
│ ├── set-xcode-analyzer -> ../@xpack-dev-tools/clang/.content/bin/set-xcode-analyzer
│ ├── split-file -> ../@xpack-dev-tools/clang/.content/bin/split-file
│ └── wasm-ld -> ../@xpack-dev-tools/clang/.content/bin/wasm-ld
└── @xpack-dev-tools
└── clang -> /Users/ilg/Library/xPacks/@xpack-dev-tools/clang/18.1.8-2.1
4 directories, 72 files
This command will also remeber the actual clang version in the
xpacks.devDependencies
section of package.json
, ensuring that
the project is locked to this version:
{
"xpacks": {
"devDependencies": {
"@xpack-dev-tools/clang": {
"specifier": "18.1.8-2.1",
"local": "link",
"platforms": "all"
}
},
}
}
On Windows, where symbolic links to files are problematic, forwarders/shims are used. For example:
...
│ clang
│ clang.cmd
│ clang.ps1
- Windows
- macOS
- GNU/Linux
To test if clang
starts properly, invoke it via the shim in the
.bin
folder:
PS C:\Users\ilg\xpm-demo-hello> .\xpacks\.bin\clang --version
xPack x86_64 clang version 18.1.8
To test if clang
starts properly, invoke it via the link in the
.bin
folder:
% ./xpacks/.bin/clang --version
xPack x86_64 clang version 18.1.8
To test if clang
starts properly, invoke it via the link in the
.bin
folder:
$ ./xpacks/.bin/clang --version
xPack x86_64 clang version 18.1.8
Add actions
In traditional development environments, adding xpacks/.bin
to the
PATH
is sufficient to allow any build tools to access the installed
executables.
However, the workflow can be further automated, by starting the build tools
via xpm run
, which automatically manages the PATH
.
For this, edit package.json
and add the clang --version
command in the
xpack.actions
section, with a name (for example cc-version
):
{
"xpacks": {
"actions": {
"cc-version": "clang --version"
}
}
}
With this definition, the compiler version can be displayed without manually entering the path:
- Windows
- macOS
- GNU/Linux
PS C:\Users\ilg\xpm-demo-hello> xpm run cc-version
> clang --version
xPack x86_64 clang version 18.1.8
% xpm run cc-version
> clang --version
xPack x86_64 clang version 18.1.8
$ xpm run cc-version
> clang --version
xPack x86_64 clang version 18.1.8
With the compiler functional, more xpack.actions
can be added to
handle the actual tasks: preparing the build environment,
performing the build, and executing the resulting program:
{
"xpacks": {
"actions": {
"cc-version": "clang --version",
"prepare": "mkdir build",
"build": "clang src/hello.c -o build/hello",
"execute": "build{{path.sep}}hello"
}
}
}
The {{path.sep}}
syntax is a LiquidJS substitution used to
accommodate platform-specific path separators. It is necessary
in the execute
command because it is parsed by the system shell.
However, it is not required in the compile command since the toolchain
also understands POSIX paths.
In this simple demo case, the prepare
action is straightforward and can
be directly executed in the terminal. However, for real-life projects,
preparing the build often involves using tools like CMake or meson.
Therefore, it is recommended as a best practice to always define a
prepare
action.
With these actions defined, the workflow becomes:
- Windows
- macOS
- GNU/Linux
PS C:\Users\ilg\xpm-demo-hello> xpm run prepare
> mkdir build
PS C:\Users\ilg\xpm-demo-hello> xpm run build
> clang src/hello.c -o build/hello
PS C:\Users\ilg\xpm-demo-hello> xpm run execute
> build\hello
Hello World!
% xpm run prepare
> mkdir build
% xpm run build
> clang src/hello.c -o build/hello
% xpm run execute
> build/hello
Hello World!
$ xpm run prepare
> mkdir build
$ xpm run build
> clang src/hello.c -o build/hello
$ xpm run execute
> build/hello
Hello World!
Visual Studio Code
For convenience, when using Visual Studio Code with the xPack C/C++ Managed Build Tools extension, the actions are displayed in the bottom left corner and can be executed with a single mouse click.
Instantiate a template
While the resulting projects above are functional, they remain quite simple.
A real-world project will likely have multiple configurations, at least to build separate debug and release executables, and possibly to run tests in various environments.
Additionally, more complex projects will probably use tools like CMake or Meson.
These types of projects can be created manually, but the process can be further automated by using project templates.
To generate the traditional Hello World! project, there is an xpack/hello-world-template-xpack project, also available from npmjs.com as @xpack/hello-world-template.
Both C and C++ are supported, with CMake and meson as build system generators.
Instantiating the template in interractive mode looks like this:
% mkdir my-project && cd my-project
% xpm init --template @xpack/hello-world-template@latest
Checking package @xpack/hello-world-template@latest metadata...
Processing @xpack/hello-world-template@0.6.1...
Programming language? (c, cpp, ?) [cpp]: c
Build System? (cmake, meson, autotools, ?) [cmake]:
Toolchain? (gcc, clang, system, ?) [gcc]: clang
Creating the C project 'my-project'...
File 'include/hello-world.h' copied.
File 'src/hello-world.c' copied.
File 'libs/adder/include/add/add.h' copied.
File 'libs/adder/src/add.c' copied.
Folder 'cmake' copied.
File 'CMakeLists.txt' generated.
File '.vscode/tasks.json' copied.
File '.vscode/settings.json' copied.
File '.gitignore' copied.
File '.npmignore' copied.
File 'README.md' generated.
File 'LICENSE' generated.
File 'package.json' generated.
For portability reasons it is recommended to use clang, gcc might not run properly on newer macOS releases.
The next step is to satisfy the project dependencies:
% xpm install
@my-scope/my-project...
+ @xpack-dev-tools/ninja-build@1.11.1-3.1
+ @xpack-dev-tools/cmake@3.28.6-1.1
+ @xpack-dev-tools/clang@18.1.8-2.1
'xpacks/@xpack-dev-tools/cmake' -> '/Users/ilg/Library/xPacks/@xpack-dev-tools/cmake/3.28.6-1.1'
'xpacks/@xpack-dev-tools/clang' -> '/Users/ilg/Library/xPacks/@xpack-dev-tools/clang/18.1.8-2.1'
'xpacks/.bin/ccmake' -> '../@xpack-dev-tools/cmake/.content/bin/ccmake'
'xpacks/@xpack-dev-tools/ninja-build' -> '/Users/ilg/Library/xPacks/@xpack-dev-tools/ninja-build/1.11.1-3.1'
'xpacks/.bin/analyze-build' -> '../@xpack-dev-tools/clang/.content/bin/analyze-build'
'xpacks/.bin/cmake' -> '../@xpack-dev-tools/cmake/.content/bin/cmake'
'xpacks/.bin/clang' -> '../@xpack-dev-tools/clang/.content/bin/clang'
'xpacks/.bin/ninja' -> '../@xpack-dev-tools/ninja-build/.content/bin/ninja'
'xpacks/.bin/cpack' -> '../@xpack-dev-tools/cmake/.content/bin/cpack'
'xpacks/.bin/clang++' -> '../@xpack-dev-tools/clang/.content/bin/clang++'
'xpacks/.bin/ctest' -> '../@xpack-dev-tools/cmake/.content/bin/ctest'
'xpacks/.bin/clang-check' -> '../@xpack-dev-tools/clang/.content/bin/clang-check'
'xpacks/.bin/clang-cl' -> '../@xpack-dev-tools/clang/.content/bin/clang-cl'
'xpacks/.bin/clang-cpp' -> '../@xpack-dev-tools/clang/.content/bin/clang-cpp'
'xpacks/.bin/clang-doc' -> '../@xpack-dev-tools/clang/.content/bin/clang-doc'
'xpacks/.bin/clang-format' -> '../@xpack-dev-tools/clang/.content/bin/clang-format'
'xpacks/.bin/clang-include-cleaner' -> '../@xpack-dev-tools/clang/.content/bin/clang-include-cleaner'
'xpacks/.bin/clang-linker-wrapper' -> '../@xpack-dev-tools/clang/.content/bin/clang-linker-wrapper'
'xpacks/.bin/clang-refactor' -> '../@xpack-dev-tools/clang/.content/bin/clang-refactor'
'xpacks/.bin/clang-rename' -> '../@xpack-dev-tools/clang/.content/bin/clang-rename'
'xpacks/.bin/clang-repl' -> '../@xpack-dev-tools/clang/.content/bin/clang-repl'
'xpacks/.bin/clang-scan-deps' -> '../@xpack-dev-tools/clang/.content/bin/clang-scan-deps'
'xpacks/.bin/clang-tblgen' -> '../@xpack-dev-tools/clang/.content/bin/clang-tblgen'
'xpacks/.bin/clang-tidy' -> '../@xpack-dev-tools/clang/.content/bin/clang-tidy'
'xpacks/.bin/clangd' -> '../@xpack-dev-tools/clang/.content/bin/clangd'
'xpacks/.bin/darwin-debug' -> '../@xpack-dev-tools/clang/.content/bin/darwin-debug'
'xpacks/.bin/diagtool' -> '../@xpack-dev-tools/clang/.content/bin/diagtool'
'xpacks/.bin/git-clang-format' -> '../@xpack-dev-tools/clang/.content/bin/git-clang-format'
'xpacks/.bin/hmaptool' -> '../@xpack-dev-tools/clang/.content/bin/hmaptool'
'xpacks/.bin/ld.lld' -> '../@xpack-dev-tools/clang/.content/bin/ld.lld'
'xpacks/.bin/ld64.lld' -> '../@xpack-dev-tools/clang/.content/bin/ld64.lld'
'xpacks/.bin/llc' -> '../@xpack-dev-tools/clang/.content/bin/llc'
'xpacks/.bin/lld' -> '../@xpack-dev-tools/clang/.content/bin/lld'
'xpacks/.bin/lld-link' -> '../@xpack-dev-tools/clang/.content/bin/lld-link'
'xpacks/.bin/lldb' -> '../@xpack-dev-tools/clang/.content/bin/lldb'
'xpacks/.bin/lldb-argdumper' -> '../@xpack-dev-tools/clang/.content/bin/lldb-argdumper'
'xpacks/.bin/lldb-instr' -> '../@xpack-dev-tools/clang/.content/bin/lldb-instr'
'xpacks/.bin/lldb-server' -> '../@xpack-dev-tools/clang/.content/bin/lldb-server'
'xpacks/.bin/lli' -> '../@xpack-dev-tools/clang/.content/bin/lli'
'xpacks/.bin/llvm-addr2line' -> '../@xpack-dev-tools/clang/.content/bin/llvm-addr2line'
'xpacks/.bin/llvm-ar' -> '../@xpack-dev-tools/clang/.content/bin/llvm-ar'
'xpacks/.bin/llvm-as' -> '../@xpack-dev-tools/clang/.content/bin/llvm-as'
'xpacks/.bin/llvm-bitcode-strip' -> '../@xpack-dev-tools/clang/.content/bin/llvm-bitcode-strip'
'xpacks/.bin/llvm-config' -> '../@xpack-dev-tools/clang/.content/bin/llvm-config'
'xpacks/.bin/llvm-cov' -> '../@xpack-dev-tools/clang/.content/bin/llvm-cov'
'xpacks/.bin/llvm-cxxdump' -> '../@xpack-dev-tools/clang/.content/bin/llvm-cxxdump'
'xpacks/.bin/llvm-cxxfilt' -> '../@xpack-dev-tools/clang/.content/bin/llvm-cxxfilt'
'xpacks/.bin/llvm-cxxmap' -> '../@xpack-dev-tools/clang/.content/bin/llvm-cxxmap'
'xpacks/.bin/llvm-debuginfo-analyzer' -> '../@xpack-dev-tools/clang/.content/bin/llvm-debuginfo-analyzer'
'xpacks/.bin/llvm-debuginfod' -> '../@xpack-dev-tools/clang/.content/bin/llvm-debuginfod'
'xpacks/.bin/llvm-debuginfod-find' -> '../@xpack-dev-tools/clang/.content/bin/llvm-debuginfod-find'
'xpacks/.bin/llvm-diff' -> '../@xpack-dev-tools/clang/.content/bin/llvm-diff'
'xpacks/.bin/llvm-dis' -> '../@xpack-dev-tools/clang/.content/bin/llvm-dis'
'xpacks/.bin/llvm-dlltool' -> '../@xpack-dev-tools/clang/.content/bin/llvm-dlltool'
'xpacks/.bin/llvm-dwarfutil' -> '../@xpack-dev-tools/clang/.content/bin/llvm-dwarfutil'
'xpacks/.bin/llvm-lib' -> '../@xpack-dev-tools/clang/.content/bin/llvm-lib'
'xpacks/.bin/llvm-libtool-darwin' -> '../@xpack-dev-tools/clang/.content/bin/llvm-libtool-darwin'
'xpacks/.bin/llvm-nm' -> '../@xpack-dev-tools/clang/.content/bin/llvm-nm'
'xpacks/.bin/llvm-objcopy' -> '../@xpack-dev-tools/clang/.content/bin/llvm-objcopy'
'xpacks/.bin/llvm-objdump' -> '../@xpack-dev-tools/clang/.content/bin/llvm-objdump'
'xpacks/.bin/llvm-otool' -> '../@xpack-dev-tools/clang/.content/bin/llvm-otool'
'xpacks/.bin/llvm-profdata' -> '../@xpack-dev-tools/clang/.content/bin/llvm-profdata'
'xpacks/.bin/llvm-ranlib' -> '../@xpack-dev-tools/clang/.content/bin/llvm-ranlib'
'xpacks/.bin/llvm-rc' -> '../@xpack-dev-tools/clang/.content/bin/llvm-rc'
'xpacks/.bin/llvm-readelf' -> '../@xpack-dev-tools/clang/.content/bin/llvm-readelf'
'xpacks/.bin/llvm-readobj' -> '../@xpack-dev-tools/clang/.content/bin/llvm-readobj'
'xpacks/.bin/llvm-remarkutil' -> '../@xpack-dev-tools/clang/.content/bin/llvm-remarkutil'
'xpacks/.bin/llvm-sim' -> '../@xpack-dev-tools/clang/.content/bin/llvm-sim'
'xpacks/.bin/llvm-size' -> '../@xpack-dev-tools/clang/.content/bin/llvm-size'
'xpacks/.bin/llvm-strings' -> '../@xpack-dev-tools/clang/.content/bin/llvm-strings'
'xpacks/.bin/llvm-strip' -> '../@xpack-dev-tools/clang/.content/bin/llvm-strip'
'xpacks/.bin/llvm-symbolizer' -> '../@xpack-dev-tools/clang/.content/bin/llvm-symbolizer'
'xpacks/.bin/llvm-tblgen' -> '../@xpack-dev-tools/clang/.content/bin/llvm-tblgen'
'xpacks/.bin/llvm-tli-checker' -> '../@xpack-dev-tools/clang/.content/bin/llvm-tli-checker'
'xpacks/.bin/llvm-windres' -> '../@xpack-dev-tools/clang/.content/bin/llvm-windres'
'xpacks/.bin/run-clang-tidy' -> '../@xpack-dev-tools/clang/.content/bin/run-clang-tidy'
'xpacks/.bin/scan-build-py' -> '../@xpack-dev-tools/clang/.content/bin/scan-build-py'
'xpacks/.bin/set-xcode-analyzer' -> '../@xpack-dev-tools/clang/.content/bin/set-xcode-analyzer'
'xpacks/.bin/split-file' -> '../@xpack-dev-tools/clang/.content/bin/split-file'
'xpacks/.bin/wasm-ld' -> '../@xpack-dev-tools/clang/.content/bin/wasm-ld'
The final step is to run the tests:
% xpm run test-all
> xpm run test-debug
> xpm run prepare --config debug
> cmake -S . -B build/debug -G Ninja -D CMAKE_BUILD_TYPE=Debug -D CMAKE_EXPORT_COMPILE_COMMANDS=ON -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang.cmake
-- The C compiler identification is Clang 18.1.8
-- The CXX compiler identification is Clang 18.1.8
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Users/ilg/tmp/my-project/xpacks/.bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Users/ilg/tmp/my-project/xpacks/.bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The ASM compiler identification is Clang with GNU-like command-line
-- Found assembler: /Users/ilg/tmp/my-project/xpacks/.bin/clang
-- Build type: Debug
-- Project path: /Users/ilg/tmp/my-project
-- PATH: /Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/.nvm/versions/node/v22.11.0/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
-- CMake version: 3.28.6
-- Compiler: Clang 18.1.8
-- A> hello-world
-- Configuring done (2.5s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/ilg/tmp/my-project/build/debug
> xpm run build --config debug
> cmake -S . -B build/debug -G Ninja -D CMAKE_BUILD_TYPE=Debug -D CMAKE_EXPORT_COMPILE_COMMANDS=ON
-- Build type: Debug
-- Project path: /Users/ilg/tmp/my-project
-- PATH: /Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/.nvm/versions/node/v22.11.0/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
-- CMake version: 3.28.6
-- Compiler: Clang 18.1.8
-- A> hello-world
-- Configuring done (0.2s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/ilg/tmp/my-project/build/debug
> cmake --build build/debug --verbose
Change Dir: '/Users/ilg/tmp/my-project/build/debug'
Run Build Command(s): /Users/ilg/tmp/my-project/xpacks/.bin/ninja -v
[1/3] /Users/ilg/tmp/my-project/xpacks/.bin/clang -DDEBUG -I/Users/ilg/tmp/my-project/include -I/Users/ilg/tmp/my-project/libs/adder/include -O0 -g3 -std=c11 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -MD -MT CMakeFiles/hello-world.dir/libs/adder/src/add.c.o -MF CMakeFiles/hello-world.dir/libs/adder/src/add.c.o.d -o CMakeFiles/hello-world.dir/libs/adder/src/add.c.o -c /Users/ilg/tmp/my-project/libs/adder/src/add.c
[2/3] /Users/ilg/tmp/my-project/xpacks/.bin/clang -DDEBUG -I/Users/ilg/tmp/my-project/include -I/Users/ilg/tmp/my-project/libs/adder/include -O0 -g3 -std=c11 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -MD -MT CMakeFiles/hello-world.dir/src/hello-world.c.o -MF CMakeFiles/hello-world.dir/src/hello-world.c.o.d -o CMakeFiles/hello-world.dir/src/hello-world.c.o -c /Users/ilg/tmp/my-project/src/hello-world.c
[3/3] : && /Users/ilg/tmp/my-project/xpacks/.bin/clang -O0 -g3 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Wl,-dead_strip CMakeFiles/hello-world.dir/src/hello-world.c.o CMakeFiles/hello-world.dir/libs/adder/src/add.c.o -o hello-world && :
-macosx_version_min has been renamed to -macos_version_min
-macosx_version_min has been renamed to -macos_version_min
> xpm run execute --config debug
> build/debug/hello-world
Hello World!
(in debug mode)
Check adder lib: 41 + 1 = 42
> xpm run test-release
> xpm run prepare --config release
> cmake -S . -B build/release -G Ninja -D CMAKE_BUILD_TYPE=Release -D CMAKE_EXPORT_COMPILE_COMMANDS=ON -D CMAKE_TOOLCHAIN_FILE=cmake/toolchains/clang.cmake
-- The C compiler identification is Clang 18.1.8
-- The CXX compiler identification is Clang 18.1.8
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Users/ilg/tmp/my-project/xpacks/.bin/clang - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Users/ilg/tmp/my-project/xpacks/.bin/clang++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- The ASM compiler identification is Clang with GNU-like command-line
-- Found assembler: /Users/ilg/tmp/my-project/xpacks/.bin/clang
-- Build type: Release
-- Project path: /Users/ilg/tmp/my-project
-- PATH: /Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/.nvm/versions/node/v22.11.0/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
-- CMake version: 3.28.6
-- Compiler: Clang 18.1.8
-- A> hello-world
-- Configuring done (2.3s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/ilg/tmp/my-project/build/release
> xpm run build --config release
> cmake -S . -B build/release -G Ninja -D CMAKE_BUILD_TYPE=Release -D CMAKE_EXPORT_COMPILE_COMMANDS=ON
-- Build type: Release
-- Project path: /Users/ilg/tmp/my-project
-- PATH: /Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/tmp/my-project/xpacks/.bin:/Users/ilg/.nvm/versions/node/v22.11.0/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/local/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/bin:/var/run/com.apple.security.cryptexd/codex.system/bootstrap/usr/appleinternal/bin
-- CMake version: 3.28.6
-- Compiler: Clang 18.1.8
-- A> hello-world
-- Configuring done (0.1s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/ilg/tmp/my-project/build/release
> cmake --build build/release --verbose
Change Dir: '/Users/ilg/tmp/my-project/build/release'
Run Build Command(s): /Users/ilg/tmp/my-project/xpacks/.bin/ninja -v
[1/3] /Users/ilg/tmp/my-project/xpacks/.bin/clang -I/Users/ilg/tmp/my-project/include -I/Users/ilg/tmp/my-project/libs/adder/include -O3 -DNDEBUG -std=c11 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -MD -MT CMakeFiles/hello-world.dir/libs/adder/src/add.c.o -MF CMakeFiles/hello-world.dir/libs/adder/src/add.c.o.d -o CMakeFiles/hello-world.dir/libs/adder/src/add.c.o -c /Users/ilg/tmp/my-project/libs/adder/src/add.c
[2/3] /Users/ilg/tmp/my-project/xpacks/.bin/clang -I/Users/ilg/tmp/my-project/include -I/Users/ilg/tmp/my-project/libs/adder/include -O3 -DNDEBUG -std=c11 -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -MD -MT CMakeFiles/hello-world.dir/src/hello-world.c.o -MF CMakeFiles/hello-world.dir/src/hello-world.c.o.d -o CMakeFiles/hello-world.dir/src/hello-world.c.o -c /Users/ilg/tmp/my-project/src/hello-world.c
[3/3] : && /Users/ilg/tmp/my-project/xpacks/.bin/clang -O3 -DNDEBUG -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX14.4.sdk -Wl,-search_paths_first -Wl,-headerpad_max_install_names -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -flto -Wl,-dead_strip CMakeFiles/hello-world.dir/src/hello-world.c.o CMakeFiles/hello-world.dir/libs/adder/src/add.c.o -o hello-world && :
-macosx_version_min has been renamed to -macos_version_min
-macosx_version_min has been renamed to -macos_version_min
> xpm run execute --config release
> build/release/hello-world
Hello World!
(in release mode)
(no asserts)
Check adder lib: 41 + 1 = 42
Final considerations
The xpm workflow described above can be successfully applied in various scenarios:
- Source code libraries: These can be included as dependencies in other projects.
- Projects with executables: These can also be included as dependencies in other projects.
- Final projects: These produce various artefacts and can run natively or on embedded platforms.
Once the mechanism for defining xpack.actions
is understood,
it becomes possible to implement highly complex workflows.
For example, you can create intricate build configurations for
very elaborate multi-platform tests.
For final projects that are not intended to be used as dependencies in
other projects, having a complex logic in the top-level package.json
is not a significant issue.
However, for projects intended to be used as dependencies
in other projects, it is recommended to
keep only the user-related metadata
in the top-level package.json
and move all development
metadata to separate folders.
Separate tests/package.json
To reduce the clutter, it is recommended to move all test-related metadata
to a separate tests
folder, with its own package.json
.
Separate build_assets/package.json
Similarly, if the project produces executables to be used as dependencies,
it is recommended to move all build related files into a separate folder,
for example build-assets
, with its own package.json
.