Mama - A modular C++ build tool so simple even your mama can use it
Mama turns a tree of C++ libraries - your own and third-party - into a single
mama build. It clones the sources, configures them, builds them in the right order
across every platform and compiler you target, and links the results into your project.
No central package repository, no Docker containers, no hand-written toolchain glue -
just git repos, a minimal set of system libs, and the compilers you already have.
Building is as simple as mama build windows - no ceremony~! Trivial CMake projects and
header-only or stand-alone C libraries are picked up automatically; larger projects add a
small mamafile.py to declare their dependencies and build steps.
- One command, the whole DAG. Mama resolves C++ dependencies into a build graph and drives
it end to end - clone, configure, compile, in dependency order.
mama build <target>does just that target's subtree, nothing more. - Everything parallel. Clones, configures and compiles all run at once under one scheduler - a leaf builds while a deeper dep still clones. Longest poles launch first; the core budget is RAM-capped so a wide build can't OOM the box.
- Multi-platform, multi-compiler - no Docker. Toolchains used as designed:
linux,linux-clang,windows,androidand other cross-builds land side by side, never clobbering. Three platforms at once? Run three builds,mama build <platform>each. Sanitizers (asan/lsan/tsan/ubsan) and coverage are plain flags. - Any build system. CMake, GNU Make, MSBuild, or a custom
build()step - all through the same scheduler and live display. - Faster CMake configures. Compiler detection (~5s of a ~6.5s cold configure) runs once per toolchain and is reused across every fresh build dir, cutting it down to almost nothing.
- In-source, project-scoped, reproducible. Dependencies pull from git (pinned by tag/branch/commit) or local folders; heavy libs like OpenCV and FFmpeg build easily from source, so a fresh checkout builds identically - only a minimal set of system libs is assumed.
- Resilient & cached. Fail-fast Ctrl+C, self-healing build dirs after an interrupted
configure, and
mama uploadto a private artifactory server so matching commits are fetched instead of rebuilt. - Rich build stats.
mama build buildstatsprints per-package timing bars plus a frontend/backend/link breakdown (MSVC vcperf, Clang-ftime-trace) - the slowest TUs, costliest headers, heaviest codegen. - Batteries included. Correct-order linking via
MAMA_INCLUDES/MAMA_LIBS,clang-tidyand coverage as flags, andmama initto adopt an existing CMake project in one step.
For additional documentation explore: build_target.py
Anyone who develops cross-platform C++ libraries or applications which target any combination of [Windows, Linux, macOS, iOS, Android, Raspberry, Oclea, Xilinx, MIPS, i.MX8MP]. And anyone who is not satisfied with system-wide dependencies and linker bugs caused by incompatible system-wide libraries on Linux.
If you require an easy to use, reproducible project/namespace scoped package+build system, this is for you.
Your builds will not rely on hard to setup system packages, all you need to do is type mama build.
- Windows (64-bit x86_64, 32-bit x86, 64-bit arm64, 32-bit armv7) default is latest MSVC
- Linux (Ubuntu) (64-bit x86_64, 32-bit x86, 64-bit arm64) both GCC and Clang
- MacOS (64-bit x86_64, 64-bit arm64) via config.macos_version
- iOS (64-bit arm64) via config.ios_version
- Android (64-bit arm64, 32-bit armv7) via env ANDROID_NDK_HOME or ANDROID_HOME
- Raspberry (32-bit armv7) via env RASPI_HOME
- Oclea (64-bit arm64) via config.set_oclea_toolchain() or env OCLEA_HOME
- i.MX8M Plus (64-bit arm64 NXP i.MX8M Plus) via config.set_imx8mp_toolchain() or env IMX8MP_SDK_HOME
- MIPS (mips, mipsel, mips64, mips64el) via config.set_mips_toolchain()
- Xilinx (64-bit arm64 Zynq UltraScale+ MPSoC) via config.set_xilinx_toolchain() or env XILINX_HOME
Single platform projects with platform specific build configuration and system wide dependency management such as Linux exclusive G++ projects using apt-get libraries or iOS-only apps using cocoapods.
Provides a mechanism to upload pre-built packages to a private artifactory server through mama upload mypackage. These packages will be automatically used if a git:package commit hash matches.
- Get Python 3.10+ and PIP
$ pip install mama --upgrade$ cd yourproject$ mama initwhich creates amamafile.pyand patches your CMakeLists.txt- (optional) Manual setup: Create your own
mamafile.py(examples below) and add this to your CMakeLists.txt:
include(mama.cmake)
include_directories(${MAMA_INCLUDES})
target_link_libraries(YourProject PRIVATE ${MAMA_LIBS})$ mama buildand enjoy!$ mama opento open your project in an IDE / VSCode
mama init Initialize a new project. Tries to create mamafile.py and CMakeLists.txt
mama build Build main project only. Clones missing deps, but does not git pull.
mama build x86 opencv Cross compile build target opencv to x86 architecture
mama build android Cross compile to arm64 android NDK (default API level 29)
mama build android-31 Cross compile to arm64 with Android API level 31
mama build android-26 arm Cross compile to armv7 android NDK API level 26
mama update Update all dependencies by doing git pull and build.
mama clean Cleans main project only.
mama clean x86 opencv Cleans opencv for x86 architecture.
mama clean all Cleans EVERYTHING in the dependency chain for current arch.
mama rebuild Cleans, update and build main project only.
mama rebuild deps_only Cleans and rebuilds all dependencies, but not the main project.
mama rebuild dep1 deps_only Cleans and rebuilds only dep1's dependencies, skipping dep1 itself.
mama build dep1 deps_only Build only dep1's dependencies, skipping dep1 itself.
mama configure deps_only Re-runs CMake configure on all dependencies, but not the main project.
mama build dep1 Build dep1 only. Clones if missing, but does not git pull.
mama update dep1 Update and build the specified target.
mama serve android Update, build and deploy for Android.
mama deploy Runs PAPA deploy stage.
mama configure Run CMake configure on dependencies to reconfigure and build
mama configure tsan CMake Reconfigure dependencies with thread sanitizer enabled
mama wipe dep1 Wipe target dependency completely and clone again.
mama upload dep1 Deploys and uploads dependency to Artifactory server.
mama list List all mama dependencies on this project.
mama dirty dep1 Mark a target for rebuild even if it was up to date.
mama version Show the mama package version.
mama test Run tests on main project.
mama test=arg Run tests on main project with an argument.
mama test="arg1 arg2" Run tests on main project with multiple arguments.
mama test dep1 Run tests on target dependency project.
mama test="mytest" test_until_failure=100 Run tests in a loop until failure, useful for catching flaky tests.
mama dep1 start=dbtool Call target project mamafile start() with args [`dbtool`].
Call mama help for more usage information.
release (default) Build with CMake RelWithDebInfo configuration.
debug Build with CMake Debug configuration.
clang Prefer Clang compiler on Linux.
gcc Prefer GCC compiler on Linux.
x86 | x64 | arm | arm64 Select target architecture.
arch=<arch> Override cross-compiling architecture explicitly.
jobs=N Limit maximum parallel compilations.
with_tests Forces -DENABLE_TESTS=ON and -DBUILD_TESTS=ON.
fortran Enable automatic Fortran compiler detection.
flags="-Wextra -O3" Pass additional compiler flags.
clang-tidy Enable clang-tidy static analysis during build.
silent Greatly reduces output verbosity.
verbose Greatly increases output verbosity.
buildstats After the build, print per-package timing bars and a deep compiler breakdown.
parallel Load dependencies in parallel.
deps_only Only execute build/rebuild/clean on dependencies, skip the main target.
When combined with a target name, applies to that target's dependencies only.
unshallow Allow unshallowing shallow git clones.
https-override Rewrite all add_git() ssh urls (git@host:path) to https://host/path.
ssh-override Rewrite all add_git() https urls to ssh (git@host:path).
The https-override / ssh-override flags rewrite the git access protocol of every
add_git() dependency at build time, without editing any mamafile. Use them when an
environment can only reach git over one protocol: https-override for hosts that only
allow https access tokens (no ssh keys), ssh-override for hosts where https is blocked
and ssh keys are required. They work for GitHub, GitLab (including nested groups),
Bitbucket and self-hosted/custom-port servers; local paths (/srv/.., file://, C:/..)
are left untouched. Embedded https credentials and ssh custom ports are dropped on
conversion, and an existing clone's origin remote is re-pointed so fetch/pull follow
the chosen protocol.
mama build https-override git@github.com:example/repo.git -> https://github.com/example/repo.git
mama build ssh-override https://github.com/RedFox20/ReCpp.git -> git@github.com:RedFox20/ReCpp.git
if_needed Only upload if package does not already exist on server.
art Always fetch packages from artifactory; failure will throw.
noart Temporarily ignore artifactory package fetching, however CACHE will still be used and fetches check for git staleness.
sanitize=address Enable -fsanitize=<type> for GCC/Clang.
asan Shorthand for sanitize=address.
lsan Shorthand for sanitize=leak.
tsan Shorthand for sanitize=thread.
ubsan Shorthand for sanitize=undefined.
coverage Build with GCC --coverage option.
coverage-report[=src_root] Generate coverage report using gcovr.
mama build buildstats prints a timing report after the build finishes.
mama build buildstats # timing report for the whole dependency chain
mama rebuild all buildstats # full rebuild, so every package shows real compile time
mama build buildstats opencv # scope the deep breakdown to a single target
Stage 1 - per-package bars. One normalized horizontal bar per package, slowest first, segmented into load (git/artifactory), configure (CMake) and build (compile+link), with the package's total wall time on the right. Bar length scales against the slowest package, so the long poles are obvious at a glance. Packages faster than 0.33s are omitted as noise. On UTF-8 terminals the segments use block shades, on legacy Windows code pages they fall back to ASCII.
Build times ░ load ▒ configure ▓ build
opencv ░▒▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ 2m 12s
ReCpp ░▒▒▓▓▓▓▓▓ 31.4s
Stage 2 - deep compiler breakdown. Where the compile time actually went: frontend (parse) vs backend (codegen) vs link, the achieved build parallelism, the slowest translation units, the costliest headers (total parse time and include count) and the costliest codegen symbols. This stage is compiler-specific:
- MSVC - the build is wrapped in a vcperf
/timetracesession and the trace is written topackages/<project>/<platform>/mama_timetrace.json. vcperf must be onPATH, in the MSVC toolset, or pointed at by theVCPERFenv var; a one-time elevatedvcperf /grantusercontrolis the prerequisite for capturing without admin rights. If vcperf isn't found, Stage 1 still prints and Stage 2 is skipped with a warning. - Clang - the build is instrumented with
-ftime-traceand the per-TU JSONs written during this run are collected from the build dirs. Usemama build clang buildstatson Linux. - GCC - no per-file trace exists, so only Stage 1 prints.
Both stages only see what was actually compiled. An up-to-date incremental build reports
no compiler activity captured - use rebuild when you want to profile a full build.
Mama supports running clang-tidy static analysis during the build. When enabled, CMake sets CMAKE_C_CLANG_TIDY and CMAKE_CXX_CLANG_TIDY so that clang-tidy runs on every compiled source file.
mama build clang-tidy # Run clang-tidy analysis during build
mama build clang-tidy debug # Combine with other flags
Clang-tidy is resolved in this order:
- System
PATHlookup CLANG_TIDYenvironment variable
If clang-tidy is not found, a warning is printed and the build proceeds without static analysis.
Place a .clang-tidy configuration file in your project root to control which checks are enabled:
Checks: >
cppcoreguidelines-avoid-reference-coroutine-parameters
WarningsAsErrors: >
cppcoreguidelines-avoid-reference-coroutine-parameters
ExtraArgsBefore:
- -Wno-unknown-warning-optionYou can also enable clang-tidy programmatically from a mamafile:
def settings(self):
self.config.set_clang_tidy_path() # auto-detect from PATH or CLANG_TIDY env
self.config.set_clang_tidy_path('/usr/bin/clang-tidy-18') # explicit path install-clang-<ver> Install Clang <ver> for Ubuntu. Ex: install-clang-18
install-gcc-<ver> Install GCC <ver> for Linux. Ex: install-gcc-13
install-msbuild Install MSBuild for Linux.
install-ndk-<ver> Install Android NDK <ver> for Linux or Windows. Ex: install-ndk-25c. Use install-ndk- to list available versions.
When a mamafile relies on newer mamabuild features, declare the minimum version. The build aborts during target load - before any configure/build work - with an upgrade hint if mama is too old:
def settings(self):
self.requires_version('0.13.01')Target myapp requires mamabuild >= 0.13.01, but this is 0.12.5. Upgrade with: pip install --upgrade mama
Versions compare segment-wise as numbers, so 0.13.01 correctly outranks 0.9.5 and a shorter
version zero-pads (0.13 < 0.13.01).
Note:
requires_versionitself exists only from 0.13.01 onward. On an older mama the mamafile fails withAttributeError: ... has no attribute 'requires_version'- which is still the signal to upgrade.
# Git dependency with full options:
self.add_git('ReCpp', 'https://github.com/RedFox20/ReCpp.git',
git_branch='master', # track a branch (default: repo default branch)
git_tag='v1.2.3', # pin to a specific git tag
git_commit='abc123', # OR pin to a specific commit hash (alias of git_tag argument)
mamafile='recpp.py', # explicit mamafile path (default: auto-detect {src}/mamafile.py)
shallow=True, # shallow clone with --depth 1 (default: True)
args=['CXX20']) # pass custom arguments to child target's self.args
# Local dependency with full options:
self.add_local('utils', 'libs/utils',
mamafile=None, # explicit mamafile path (default: auto-detect {src}/mamafile.py)
always_build=False, # force rebuild every time (useful for active sub-projects)
args=[]) # pass custom arguments to child target's self.args
# Artifactory prebuilt package:
self.add_artifactory_pkg('opencv', version='df76b66') # by commit hash
self.add_artifactory_pkg('opencv', fullname='opencv-linux-x64-release-df76b66') # by full nameThe args parameter passes custom arguments to the child target, accessible via self.args:
class MyLib(mama.BuildTarget):
def configure(self):
if 'CXX20' in self.args:
self.enable_cxx20()
if 'SHARED' in self.args:
self.add_cmake_options('BUILD_SHARED_LIBS=ON')Mamafile discovery: When adding a dependency without an explicit mamafile= path,
mama automatically checks for {src}/mamafile.py in the parent project.
# Get a dependency's exported include path and library paths:
zinclude, zlibrary = self.get_target_products('zlib')
self.add_cmake_options(f'ZLIB_INCLUDE_DIR={zinclude}')
self.add_cmake_options(f'ZLIB_LIBRARY={zlibrary}')
# Or inject one dependency's products into another as CMake defines:
self.inject_products(dst_dep='libpng', src_dep='zlib',
include_path='ZLIB_INCLUDE_DIR',
libs='ZLIB_LIBRARY')
# Retrieve all injected product defines collected via inject_products():
defines = self.get_product_defines() # returns list of CMake definesMamafile classes extend mama.BuildTarget and can override these methods:
| Method | Description |
|---|---|
dependencies(self) |
Add git, local, or artifactory dependencies |
settings(self) |
Define settings (called first, after clone) |
configure(self) |
Pre-build CMake configuration options |
build(self) |
Override the default cmake_build() behavior |
package(self) |
Post-build: define exported includes, libs, assets |
install(self) |
Override the default cmake_install() step |
deploy(self) |
Custom deployment logic |
clean(self) |
Custom pre-clean steps |
test(self, args) |
Test runner invoked by mama test |
start(self, args) |
Custom entrypoint invoked by mama start=<arg> |
init(self) |
Initialization after mamafile is loaded |
| Attribute | Default | Description |
|---|---|---|
workspace |
None |
Local workspace folder for build intermediates |
global_workspace |
None |
System-wide workspace folder name |
cmake_build_type |
'RelWithDebInfo' |
CMake build type (or 'Debug' with debug flag) |
cmake_lists_path |
'CMakeLists.txt' |
Path to the CMakeLists.txt relative to source |
cmake_command |
'cmake' |
CMake executable path |
enable_exceptions |
True |
Enable C++ exceptions |
enable_ninja_build |
True (if found) |
Use Ninja generator when available |
enable_unix_make |
False |
Force Unix Makefiles generator |
enable_cxx_build |
True |
Enable C++ compiler |
enable_multiprocess_build |
True |
Enable parallel compilation |
clean_intermediate_files |
False |
Clean intermediate build files after build |
version |
None |
Custom version string for packaging |
args |
[] |
Arguments passed from parent via add_git(args=) / add_local(args=) |
Use these boolean properties in mamafiles for platform-conditional logic:
self.windows, self.linux, self.macos, self.ios, self.android,
self.raspi, self.oclea, self.xilinx, self.imx8mp, self.mips, self.yocto_linux
Host OS detection: self.os_windows, self.os_linux, self.os_macos
self.enable_cxx11() # or enable_cxx14(), enable_cxx17(), enable_cxx20(), enable_cxx23(), enable_cxx26()
# Query current C++ standard:
if self.is_enabled_cxx20(): # or is_enabled_cxx11/14/17/23/26()
self.add_cmake_options('USE_CXX20_FEATURES=ON')self.add_cxx_flags('-Wall', '-Wextra') # C++ only flags
self.add_c_flags('-std=c11') # C only flags
self.add_cl_flags('-fPIC') # Both C and C++ flags
self.add_ld_flags('-lm') # Linker flags
self.add_platform_cxx_flags(linux='-fPIC', windows='/W4') # Per-platform C++ flags
self.add_platform_ld_flags(linux='-pthread') # Per-platform linker flagsself.add_cmake_options('BUILD_SHARED_LIBS=ON', 'OPTION=VALUE')
self.add_platform_options(linux='LINUX_OPT=ON', windows='WIN_OPT=ON')
self.enable_from_env('CUDA') # enable CMake option CUDA=ON if CUDA=1 env var is setself.export_includes(['include']) # Export include dirs from source dir
self.export_include('include', build_dir=True) # Export single include dir from build dir
self.export_include('src', as_includes_root='mylib') # Deploy as src/*.h as include/mylib/ for clean #include <mylib/mylib.h>
self.export_libs('.', ['.lib', '.a']) # Find and export libs matching patterns
self.export_libs('.', ['.lib', '.a'], order=['core', 'utils']) # Control linker order (important on Linux)
self.export_lib('lib/mylib.a') # Export a specific library file
self.export_syslib('GL') # Export a system library
self.export_syslib('GL', apt='libgl-dev') # With apt package hint on failure
self.export_syslib('optional_lib', required=False) # Silently skip if not found
self.export_asset('data/model.bin', category='models') # Export asset files
self.export_assets('data/', ['.bin', '.dat']) # Export multiple assets by pattern
self.no_export_includes() # Suppress automatic include exports
self.no_export_libs() # Suppress automatic lib exportsself.run('make install', src_dir=True) # Run a shell command
self.run_program('/usr/local/bin', './tool --flag') # Run program in a specific directory
self.gdb('bin/MyTests') # Run with GDB/LLDB debugger
self.gtest('bin/MyTests', args, gdb=True) # Run GTest executable with XML reports
self.gnu_project('zlib', '1.2.13', url='...') # Build a GNU autotools project
self.ms_build('project.vcxproj', properties={}) # Build with MSBuild (for C#/.NET apps)
self.cmake_build() # Build . with CMake (default build() implementation)
self.inject_env() # Inject platform env vars (needed for custom build() overrides)
self.get_cc_prefix() # Get cross-compiler prefix (e.g. '/usr/bin/mipsel-linux-gnu-')gdb() and gtest() automatically select the correct debugger:
- Linux: uses
gdb - macOS: uses
lldb - Windows: runs directly (no debugger)
- Cross-compile targets: skips debugger with a message
- Sanitizer active: skips debugger to avoid runtime conflicts
Pass gdb or nogdb in test/start args to override: mama test=nogdb
gtest() writes XML reports to {source_dir}/test/report.xml for CI integration.
Non-gtest arguments are auto-converted to filters: mama test=MyFixture becomes --gtest_filter="*MyFixture*".
Native --gtest_* flags are passed through unchanged.
For autotools-based projects, gnu_project() provides a complete build pipeline:
from mama.utils.gnu_project import BuildProduct
def build(self):
gp = self.gnu_project('zlib', '1.2.13',
url='https://zlib.net/zlib-1.2.13.tar.gz', # download archive
# git='https://github.com/madler/zlib.git', # or clone from git
autogen=False, # run ./autogen.sh before configure
configure='configure', # configure command (default: 'configure')
build_products=[ # files to deploy
BuildProduct('{{installed}}/lib/libz.a', '{{build}}/lib/libz.a'),
])
gp.build(options=['--static'], prefix='/usr/local')
# Or call steps individually:
# gp.configure(options=['--static'])
# gp.make(multithreaded=True)
# gp.install()BuildProduct paths support template variables: {{installed}}, {{source}}, {{build}}.
self.copy(src, dst, filter=None) # Copy files
self.copy_built_file('Release/mylib.dll', 'bin/') # Copy a build artifact
self.download_file('https://...', 'local_dir/') # Download a file
self.download_and_unzip('https://.../sdk.zip', 'sdk/') # Download and extract
self.source_dir('subpath') # Get absolute source directory path
self.build_dir('subpath') # Get absolute build directory pathself.prefer_gcc() # Prefer GCC on Linux (DEFAULT)
self.prefer_clang() # Prefer Clang on Linux
self.visibility_hidden() # Set -fvisibility=hidden
self.disable_ninja_build() # Force CMake default generator instead of Ninja (default)
self.disable_install() # Skip cmake install step
self.enable_fortran() # Enable Fortran compiler (for Fortran accelerated libraries)
self.disable_cxx_compiler() # Disable C++ (C-only project)
self.nothing_to_build() # Mark target as header-only/no-build
self.add_build_dependency(linux='lib/libmylib.a') # Add file dependency to control rebuild stalenessself.config.libname('z') # Returns 'z.lib' on MSVC or 'libz.a' on Unix
self.config.libext() # Returns 'lib' on MSVC or 'a' on Unix
self.config.get_distro_info() # Returns (name, major, minor) e.g. ('ubuntu', 22, 4)
self.config.compiler_version() # Returns e.g. 'msvc14', 'gcc11.3', 'clang15.0'self.papa_deploy('path/to/package') # Deploy package for upload
self.papa_deploy('path/to/package', # Deploy with RECURSIVE child dependency gathering:
r_includes=True, # include child dependency includes
r_dylibs=True, # include child .dll/.so/.dylib files
r_syslibs=True, # include child system library references
r_assets=True) # include child asset files
self.default_deploy() # Deploy with default settingsProject AlphaGL/mamafile.py
import mama
class AlphaGL(mama.BuildTarget):
# where to build intermediates
workspace = 'packages' # for system-wide workspace, use: global_workspace = 'mycompany'
# grab dependencies straight from git repositories
# if the projects are trivial, then no extra configuration is needed
def dependencies(self):
# set artifactory package server for prebuilt packages
# the credentials can be configured by env vars for CI, call `mama help`
self.set_artifactory_ftp('artifacts.myftp.com', auth='store')
# add packages
self.add_git('ReCpp', 'https://github.com/RedFox20/ReCpp.git', git_branch='master')
self.add_git('libpng', 'https://github.com/LuaDist/libpng.git')
self.add_git('libjpeg', 'https://github.com/LuaDist/libjpeg.git')
self.add_git('glfw', 'https://github.com/glfw/glfw.git')
# add local packages from existing directory root:
self.add_local('utils', 'libs/utils')
# add a prebuilt package, use `mama upload myproject` to generate these:
self.add_artifactory_pkg('opencv', version='df76b66')
if self.linux: # or do it conditionally for linux only:
self.add_artifactory_pkg('opencv', fullname='opencv-linux-x64-release-df76b66')
# optional: customize package exports if repository doesn't have `include` or `src`
def package(self):
self.export_libs('.', ['.lib', '.a']) # export any .lib or .a from build folder
self.export_includes(['AGL']) # export AGL as include from source folder
# platform specific system library exports:
if self.ios: self.export_syslib('-framework OpenGLES')
if self.macos: self.export_syslib('-framework OpenGL')
if self.linux: self.export_syslib('GL')
def test(self, args):
self.gdb(f'bin/AlphaGLTests {args}')If a dependency is non-trivial (it has dependencies and configuration),
you can simply place a target mamafile at: mama/{DependencyName}.py
Example dependency config AlphaGL/mama/libpng.py
import mama
class libpng_static(mama.BuildTarget):
def dependencies(self):
# custom mamafile can be passed explicitly:
self.add_git('zlib', 'https://github.com/madler/zlib.git', mamafile='zlib.py')
def configure(self):
zinclude, zlibrary = self.get_target_products('zlib')
self.add_cmake_options(f'ZLIB_INCLUDE_DIR={zinclude}')
self.add_cmake_options(f'ZLIB_LIBRARY={zlibrary}')
self.add_cmake_options('BUILD_SHARED_LIB=NO', 'PNG_TESTS=NO')
def package(self):
# libpng builds its stuff into `{build}/lib`
self.export_libs('lib', ['.lib', '.a'])
# export installed include path from build dir
self.export_include('include', build_dir=True)When developing a library where source and headers live together (e.g. src/mylib/mylib.h),
you can use as_includes_root='mylib' to deploy headers with a clean namespace:
def package(self):
self.export_libs('.', ['.lib', '.a'])
# Deploys src/*.h -> deploy/include/mylib/*.h
# Consumers use: #include <mylib/mylib.h>
self.export_include('src', as_includes_root='mylib')During development, the actual include path is set to src/ so that IDE navigation
and error messages point to the real source files. After papa deploy, only headers
are exported to include/mylib/, giving consumers clean #include <mylib/mylib.h> paths.
This is also the default behavior of default_package_includes() when only a src/ folder exists.
$ mama clang build
Mama 0.13.01 building with clang 18.1 libstdc++
+ build J4 reflect_cpp git 0.1s cfg 0.02s bld 0.01s
+ build J0 sdl_gamecontrollerdb git 0.1s cfg 0.02s bld 0.07s
+ build J1 nlohmannjson git 0.1s cfg 0.02s bld 0.02s
+ build J12 px4gpsdrivers git 0.4s cfg 0.0s bld 0.0s
+ build J4 xz_embedded git 0.09s cfg 0.02s bld 0.3s
+ build J5 shapelib git 0.08s cfg 0.07s bld 0.4s
+ build J15 zlib git 0.08s cfg 0.08s bld 0.3s
+ build J2 libevents git 0.08s cfg 0.1s bld 3.2s
+ build J31 SDL git 0.2s cfg 0.01s bld 5.7s
+ build J18 qcoro git 0.09s cfg 0.01s bld 10.3s
+ build J31 protobuf git 0.3s cfg 0.8s bld 35.3s
+ build J31 rtpvideo git 0.1s cfg 0.0s bld 0.0s
+ build J27 serviceman git 0.1s cfg 0.01s bld 0.01s
+ build J31 geographiclib git 0.07s cfg 0.09s bld 2.0s
+ build J31 sentry_native git 0.10s cfg 4.1s bld 0.8s
+ build J31 datalink git 0.4s cfg 0.0s bld 12.1s
+ build J31 qgroundcontrol loc 0.02s cfg 5.6s bld 27.2s
Built 14 target(s) in 1m 32s
def dependencies(self):
self.set_artifactory_ftp('ftp.myartifactory.com', auth='store')
self.add_git('googletest', 'git@github.com:RedFox20/googletest.git')$ mama upload googletest
- PAPA Deploy /home/mamabuild/example/packages/googletest/linux/deploy/googletest
I (googletest) include
L (googletest) lib/libgmock.a
L (googletest) lib/libgtest.a
PAPA Deployed: 1 includes, 2 libs, 0 syslibs, 0 assets
- PAPA Upload googletest-ubuntu-24-gcc14.3-x64-release-ae51a95 2.9MB
- googletest |==================================================>| 100 %
auth='store'(default): Credentials are stored in system keyring (useskeyrings.cryptfileon Linux). Stored per-URL; failed logins clear stored credentials automatically.auth='prompt': Always prompts for username and password.- Environment variables
MAMA_ARTIFACTORY_USER/MAMA_ARTIFACTORY_PASSalways take priority over both modes.
Artifactory archives follow the naming format:
{name}-{platform}-{os_major}-{compiler}-{arch}-{build_type}-{version}
Example: opencv-ubuntu-22-gcc11.3-x64-release-df76b66. Sanitized builds append -sanitized. Set version class attribute to override the default commit hash.
- Windows: Opens
.slnfrom build dir; falls back to VSCode - macOS/iOS: Opens
.xcodeprojfrom build dir; falls back to VSCode - Linux/Android: Opens VSCode
Syntax: mama open (root project) or mama open=dep1 (specific dependency)
Select the Android API level via the CLI:
mama build android-31 # arm64, API level 31
mama build android-26 arm # armv7, API level 26
mama build android # arm64, default API level 29
mama build ndk-28 # build with Android NDK-28 (requires ANDROID_HOME or ANDROID_SDK_ROOT)
mama build ndk-28.2 # build with Android NDK-28.2 specifically
The NDK is auto-detected from these environment variables (in priority order):
ANDROID_NDK_LATEST_HOME, ANDROID_NDK_HOME, ANDROID_NDK_ROOT, ANDROID_NDK,
then SDK paths: ANDROID_HOME, ANDROID_SDK_ROOT, and platform-specific defaults.
When multiple NDK versions are installed under {sdk}/ndk/, the latest version is selected.
For advanced configuration in settings():
def settings(self):
self.config.android.android_api = 'android-31' # Override API level
self.config.android.android_ndk_stl = 'c++_shared' # NDK STL (default: 'c++_shared')
self.config.set_android_toolchain('path/to/android.toolchain.cmake') # Custom toolchainPer-target NDK toolchain override is also supported via self.cmake_ndk_toolchain in a mamafile.
Override in settings() (defaults: macOS 13.0, iOS 16.0):
def settings(self):
self.config.macos_version = '14.0'
self.config.ios_version = '17.0'def settings(self):
self.config.set_android_toolchain('path/to/toolchain.cmake')
self.config.set_yocto_toolchain(toolchain_dir='path/to/sdk')
self.config.cc_path = '/usr/bin/gcc-12' # Override C compiler path
self.config.cxx_path = '/usr/bin/g++-12' # Override C++ compiler path| Variable | Description |
|---|---|
MAMA_ARTIFACTORY_USER |
Username for Artifactory server (CI usage) |
MAMA_ARTIFACTORY_PASS |
Password for Artifactory server (CI usage) |
NINJA |
Path to Ninja build executable (enables Ninja builds if Ninja is detected) |
ANDROID_HOME |
Path to Android SDK |
ANDROID_NDK_HOME |
Path to Android NDK |
ANDROID_NDK_ROOT |
Alternative Android NDK path |
ANDROID_NDK_LATEST_HOME |
Path to latest Android NDK |
RASPI_HOME |
Path to Raspberry Pi toolchain |
OCLEA_HOME |
Path to Oclea SDK |
IMX8MP_SDK_HOME |
Path to i.MX8M Plus SDK |
XILINX_HOME |
Path to Xilinx SDK |
CLANG_TIDY |
Path to clang-tidy executable (fallback if not found in PATH) |
Mama automatically generates compile_commands.json (via CMAKE_EXPORT_COMPILE_COMMANDS=ON) and updates .vscode/c_cpp_properties.json with the correct compileCommands path for IntelliSense support.
We are open for any improvements and feedback via pull requests.
The package setuptools>=65.0,<77 is required, ensure the version is correct with pip3 show setuptools.
You can set up local development with $ pip3 install -e . --no-cache-dir but make sure you have latest setuptools (>=65.0,<77) and latest pip3 (>22.3). This command will fail with older toolkits.
Install pytest and run all tests from the project root:
pip install pytest
pytestOr to run a specific test:
pytest tests/test_git_pinning/Uploading a source distribution:
- Get dependencies:
pip3 install build twine - Build sdist:
python -m build - Upload with twine:
twine upload --skip-existing dist/*It will prompt for Username and Password, unless you set up ~/.pypirc file:
[distutils]
index-servers = pypi
[pypi]
username=__token__
password=<pypi-api-token>
Quick build & upload: ./deploy.sh
