Quickstart
This goes from nothing to an installed package of a library of your own: create it, build it, test it, pack it, install it.
The whole walkthrough, recorded against a freshly built cxpm by
misc/record-quickstart-cast.sh:
Install cxpm
cxpm needs a C++23 compiler (GCC 14 or newer), pkg-config and git.
git clone --recurse-submodules https://github.com/arthurafarias/cxpm
cd cxpm
./cxpm-build.sh --install --prefix /usr/local
cxpm-build.sh compiles a first cxpm with the bare compiler; that one builds and packs cxpm from
its own manifests and installs the packages. Add --root DIR to install under another root, or
--package-manager pacman (or rpm, deb) to install it as a package of your distribution.
Building with CMake
The repository also carries a CMake build of the same projects, for working on cxpm itself with
an IDE, a debugger or ctest. It needs CMake 3.23 or newer:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j
ctest --test-dir build --output-on-failure
build/bin/cxpm --help # runs from the build tree
cmake --install build --prefix /usr/local # the same layout `cxpm install` makes
cmake --install copies files and registers nothing with a package manager; a cxpm that should
be removable as a package is installed with cxpm-build.sh --install.
bubblewrap
(bwrap) is optional and recommended: with
it, manifests and build steps run confined
.
Create a project
cxpm project create greeter --type static-library --tests --example
cd greeter
greeter/package.cpp the library
greeter/include/greeter/greeter.hpp
greeter/src/greeter.cpp
greeter/tests/package.cpp a project that tests it
greeter/tests/src/main.cpp
greeter/example/package.cpp a project that uses it
greeter/example/src/main.cpp
package.cpp is the manifest:
#include <CXPM/Project.hpp>
#include <CXPM/Target.hpp>
using namespace CXPM;
auto target = Target()
.name_set("greeter")
.version_set("0.1.0")
.type_set("static-library")
.sources_append({"src/*.cpp"})
.include_directories_append({"include"})
.create();
auto project = Project().target_set(target).members_append("example").tests_append("tests").create();
A project has one target. The tests and the example are projects too: each has its own
package.cpp whose target depends on greeter by name.
--type is executable (the default), shared-library, static-library or header-library.
Build and test
cxpm build
cxpm test
Building greeter (static-library) with g++
Installing greeter into .../greeter/.cxpm/sysroot
Building greeter-example (executable) with g++
Building greeter-tests (executable) with g++
Running greeter-tests
greeter-tests passed
1 of 1 tests projects passed
Everything cxpm writes goes under .cxpm/: objects and the built target in .cxpm/build/<name>/,
and the library installed where the example and the tests find it, in .cxpm/sysroot/. Nothing
is written to your system. A second cxpm build compiles nothing; changing one source recompiles
that object and links again.
cxpm test exits with 0 only if every tests project builds and its executable exits with 0.
Add a dependency
A dependency is a name and, optionally, a version constraint:
.dependencies_append({"zlib >= 1.2"})
cxpm dependency add "zlib >= 1.2" writes that line for you, and fetches the dependency when the
package index publishes it.
The name is a project of the same workspace, a dependency the manifest fetches, or a package installed in the sysroot, found through pkg-config. One that is fetched says where from:
#include <CXPM/Dependency.hpp>
.dependencies_append(Dependency()
.name_set("greeter")
.repository_set("https://example.org/greeter.git")
.revision_set("v0.1.0"))
cxpm fetch clones it into .cxpm/sources/ and writes the exact commit to .cxpm/lock.json;
cxpm build then builds it from its own manifest and installs it into .cxpm/sysroot. Commit
the lock file if you want everyone to build the same commit.
Pack and install
cxpm pack
cxpm install --prefix /usr/local
Packed .../greeter/.cxpm/packages/greeter-0.1.0.cxpm.tar
Packed .../greeter/.cxpm/packages/greeter-example-0.1.0.cxpm.tar
Installing greeter into /usr/local with archive
Installing greeter-example into /usr/local with archive
Every member of the workspace is packed and installed, so the example goes along as
bin/greeter-example; drop members_append("example") from the manifest to ship the library
alone.
Installed:
/usr/local/lib/libgreeter.a
/usr/local/include/greeter/greeter/greeter.hpp
/usr/local/lib/pkgconfig/greeter.pc
/usr/local/lib/cxpm/packages/greeter.json what was installed, for uninstall
Another project now depends on it with .dependencies_append({"greeter"}), and anything that
speaks pkg-config finds it with pkg-config --cflags --libs greeter.
To get a package of your distribution instead of an archive:
cxpm pack --package-manager pacman # or rpm, deb
sudo cxpm install --package-manager pacman --prefix /usr
cxpm uninstall removes what cxpm install installed, through the same package manager.
Where to go next
- The
cxpmcommand describes every stage, the manifest API, toolchains, building for another sysroot and confinement. cxpm help <command>lists the options of a command.