Skip to content

Sleek Build System -- build projects without build files

License

Notifications You must be signed in to change notification settings

mattbudish/sleek

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sleek Build System

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.

Typical Project Structure

  • project-folder/ - src OR include is/are required, all others are optional
    • build/ - build artifacts, generated by sleek, deleted on clean
    • include/ - header files exposed to down-stream dependents
    • lib/ - code to built as library, sleek builds shared by default - makes include required
    • src/ - can be code to be built into executable binary or library
    • test/ - unit tests - only built if requested
    • examples/ - reference implementations - only built if requested
    • samples/ - equivalent to examples

Commands

sleek

  • build -- build project in current directory
  • run -- run the executable binary target of this package building first if necessary
  • test -- build and run unit tests
  • clean -- remove generated artifacts
  • install -- 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 project
  • publish -- 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 index
  • upgrade -- upgrade installed packages
  • prune -- remove unused dependencies
  • list -- list all installed packages
  • index -- list all headers currently indexed and their respective package

Options

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

Features Implemented

  • 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

Features Needed

  • 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

Non-Functional Requirements Needed

  • Concurrent builds and scans
  • Error checking
  • Sanitize input
  • Unit tests
  • Handle proxies

Dependencies

Tools

  • 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

Header Only

  • p-ranav/argparse - parsing command line arguments
  • nlohmann/json - parsing/generating json

Runtime Libraries

  • libcurl - network I/O
  • libfl - for parsing code files
  • libarchive - create/extract tarballs

Notes

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 ~).

Fetch Algorithm

  • 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>

Build Algorithm

Against Local Library

  • compile code files normally
  • link objects with -L.sleek/lib -llibrary name -Wl,-rpath,$PWD/.sleek/lib

Against Global Library

  • compile code files normally
  • link objects with -llibrary name

Install Algorithm

Local

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

Global

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

Package Format

  • 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

Directories

  • /var/lib/sleek/index - global copy of package index
  • ~/.sleek/index - package files installed locally

Acknowledgements

*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.

About

Sleek Build System -- build projects without build files

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published