Build C/C++ projects without build files.
If you appreciate the power and flexibility of C++ but find the available build systems cumbersome due to their domain-specific languages (DSLs), Sleek is the solution for you. Sleek allows you to remove build files from your C++ projects while still ensuring successful builds. Additionally, Sleek addresses the lack of a package manager in C++ by providing comprehensive package management capabilities.
Sleek makes programming easier while reducing potential for errors by eliminating the need to keep build files and source code in sync.
Dependencies are inferred from header files included in the source files.
The build command fetches all dependencies not present on the system, building them if necessary.
Sleek aims to be a DSL free* build system. No DSL necessary, just write code, add header files, Sleek figures out if additional flags need to be added, or packages need to be downloaded and installed.
Sleek is written in C++17 with a little Flex (which generates C++).
What sets Sleek apart from other build systems in the C++ ecosystem is that the C++ language itself defines the build.
In order to do this, some assumptions are made.
project-folder/
- src OR include is/are required, all others are optionalbuild/
- build artifacts, generated by sleek, deleted on cleaninclude/
- header files exposed to down-stream dependentslib/
- code to built as library, sleek builds shared by default - makesinclude
requiredsrc/
- can be code to be built into executable binary or librarytest/
- unit tests - only built if requestedexamples/
- reference implementations - only built if requestedsamples/
- equivalent toexamples
build
-- build project in current directoryrun
-- run the executable binary target of this package building first if necessarytest
-- build and run unit testsclean
-- remove generated artifactsinstall
-- install the dependencies in the local sleek_packages folder-g
or--global
-- install the current package and any runtime dependencies globally--prefix PATH
-- install to prefix other than system default (/usr/local on linux)-d
or--dev-deps-only
-- only install dev dependencies (default is all)--production
-- do not install dev dependencies, only runtime dependencies-s, --build-from-source
-- Compile package from source even if a binary is provided. Dependencies will still be installed from binaries if they are available.
uninstall
-- uninstall artifacts of this build (if they have been installed)pack
-- create package based on current projectpublish
-- upload package to registry--patch
-- a patch level upgrade (the default)--minor
-- minor version upgrade, implies new functionality--major
-- major version upgrade, implies breaking changes
update
-- update package indexupgrade
-- upgrade installed packagesprune
-- remove unused dependencieslist
-- list all installed packagesindex
-- list all headers currently indexed and their respective package
These options can be applied to any command.
-n, --name NAME
-- sets the name of the project, default is the name of the current directory-b, --build-dir DIR
-- sets the directory in which artifacts will be built, default is "build"-s, --source-dir DIR
-- sets the source directory, default is "src"-l, --lib-dir DIR
-- sets the library directory (if there is one), default is "lib"-i, --include-dir DIR
-- sets the include directory (if there is one), default is "include"-t, --target TARGET
-- only applies to a specific target, default is apply to all targets
- Ability to parse arguments
- Ability to define build directory
- Ability to install header-only packages
- Ability to create header-only packages
- Given a list of header files, produce any necessary -I arguments
- Given a list of header files, determine any non-system libraries needed
- Produce any -L or -l arguments needed for non-system libraries
- Ability to install artifacts of a build
- Package build artifacts in archive
- Package registry
- Ability to publish header-only packages
- Build shared libraries
- Ability to install shared libraries
- Ability to uninstall packages without breaking dependencies
- Ability to determine where artifacts should be installed
- If there is a
main
function, build an executable, if not, build a shared library - Install dependencies globally or per project
- Support optional features of projects
- Generating documentation
- Integrate with IDEs
- Concurrent builds and scans
- Error checking
- Sanitize input
- Unit tests
- Handle proxies
- gcc - compiler/linker (clang might work)
- pkg-config - provide flags and dependencies
- Flex - parser generator (only required to build Sleek or projects that use Flex)
- Git
- p-ranav/argparse - parsing command line arguments
- nlohmann/json - parsing/generating json
- libcurl - network I/O
- libfl - for parsing code files
- libarchive - create/extract tarballs
Use pkg-config where possible to define compile arguments and dependencies.
Generate pkg-config data when installing libraries.
Be consistent with autotools for determining where to install artifacts.
One cpp/cc/cxx/c++/c/etc. file produces one object file.
If separate source code files are in same directory as main, their compiled objects should be statically linked.
Write code to target defualt g++ settings, which is gnu++17 at time of writing (the flag is necessary to use
filesystem
in the standard library).
Maintain a system wide cache of artifacts that sleek has installed globally for clean uninstalls.
Defalt to installing dependencies to subdirectory of project.
If project root folder has an src
folder and a lib
or include
or both, it is assumed that the project
creates both an executable and a library component. If there is an include
but no lib
it will be a
header-only library. Sleek assumes source code for executable program is in the src
subdirectory.
If there is only a src
subdirectory, the project can create either an executable or a library. If there
is a main
function in one of the code files, it will be built as an executable, if not, it will be built
as a library exposing any headers. One or more headers should always be included with a library, but Sleek
doesn't enforce this.
Sleek is built by CMake, for now. This is because sleek depends on Flex (libfl-dev on apt). Adding this capability is too complex to fit into the early goals of this project. Don't take this as an endorsement for CMake.
Create the ability to build and/or install projects that are not able to be built directly by Sleek. As part of the Sleek package, include instructions for how to build the project under whatever build system the developers used, whether that be CMake, Autotools, plain Make, or whatever. If a package is available in the native OS package manager, prefer to use that where possible, producing instructions to install it from the native package manager.
To bootstrap Sleek on systems where no binary package is available, or for code tweakers that like to build stuff from source, develop a bootstrap script. This script should download the Sleek source, check for all dependencies, gcc or clang, cl if this is ever ported to Windows, Git, pkg-config, Flex and the required shared libraries.
It is generally recommended to install dependencies locally to the project folder to minimize the likelyhood of version conflicts. Sleek by default installs the latest stable version, but may be configured to insatall any version available.
Meta data such as version, description, homepage, and license should all come from comments or variables in the
code. Executables should be able to provide this information with arguments like -v
, additional arguments may
need to be added. Libraries should be able to provide this data when linked to a simple driver program.
Package definitions (name.json files) go in /var/lib/sleek/index. There will also be a patched (with additional data about the installation) version of this in any projects .sleek directory when installed locally. When in- stalled globally a patched package definition will be writen to /usr/local/lib/sleek.
When building libraries, add the -fpic
flag to all compilation steps for objects that will go into the
library. This flag is only necessary when compiling, not necessary for linking.
To minimize chance for version conflict, dependencies installed locally under the .sleek folder of the project supersede any dependencies installed globally. This way, if a specific version is required for some reason, that may be used instead of what the rest of the system is using.
The default behavior for versioning is that each time a package is published, the patch version is incremented by one. This bay be overridden by passing an option to the publish command. Package dependencies by default will be compatible with everything greater than a particular version in the same minor range of the version first installed (semver ~).
- Check the ./.sleek/index directory to see if the package is installed locally
- Check /var/lib/sleek/package-index directory to see if the package is installed globally
- Check the system pkg-config to see if the dependency is installed globally by another package manager or build system
- Then, check the package registry, if it's there download and extract the tarball into ./.sleek/
- If there is no binary package available, download and extract source code release into ./.sleek/src/<package name>
- compile code files normally
- link objects with -L.sleek/lib -llibrary name -Wl,-rpath,$PWD/.sleek/lib
- compile code files normally
- link objects with -llibrary name
Algorithm for installing executable with a dynamic library locally.
- build library
- copy library to .sleek/lib
- build executable linking to local library
- copy executable to .sleek/bin
Algorithm for installing executable with a dynamic library globally.
- build library
- sudo copy library to /usr/local/lib
- sudo ldconfig
- build executable linking to global library
- sudo copy executable to /usr/local/bin
- index/ - *.json package definitions patched with data about how their packages were installed
- include/ - header files
- lib/ - shared and static libraries
- pkgconfig/ - *.pc files
- bin/ - executables
- share/ - shared metadata files
- pkgconfig/ - *.pc files
- /var/lib/sleek/index - global copy of package index
- ~/.sleek/index - package files installed locally
- Inspired by Rachel by the Bay's approch to building C++ projects (https://rachelbythebay.com/bb/).
*If your project does not follow the typical project structure, it may still be possible to build it with Sleek, though, this will require manually configuring a JSON file. If this is the only time you ever have to edit a JSON file, you're winning at life, but you already knew that.