runcpp is an open-source build automation tool designed to simplify the process of generating executables and other non-source files from source code. Written in C++, it provides a fast, memory-safe, and cross-platform solution for managing your build process with a simple and intuitive syntax.
The tool relies on a custom-written parser and process creation mechanisms, leveraging the openutils library to ensure memory safety without leaks or invalid memory access. It is compatible with Windows, Linux, and macOS, using native APIs (windows.h on Windows, fork() and execvp() on Unix-like systems) for optimal performance.
- Simple Syntax: A user-friendly configuration syntax that is easy to read and maintain.
- Cross-Platform: Seamlessly works on Windows, Linux, and macOS.
- Memory Safe: Built to prevent invalid memory access and leaks.
- Fast & Optimized: Custom parser and native process calls ensure high performance.
- Target-Based Builds: Define and call specific build targets.
- Dependency Checking: Use the
dependskeyword to verify the existence of tools, files, or directories. - Conditional Compilation: Use
if-elsestatements based on OS or other variables. - Shell Command Integration: Capture and use the output of shell commands within your build script using
shell. - File Imports: Structure your build logic by importing other configuration files.
- Serialization: Speed up execution by pre-parsing and serializing configuration files into a faster binary format.
To build runcpp from source, you will need a C++20 compliant compiler (like GCC, Clang, or MSVC) and the openutils library headers available in your include path.
-
Clone the repository:
git clone https://github.com/Dark-CodeX/runcpp.git cd runcpp -
Compile the source code:
runcppuses itself for building. For the initial build, you can compile all source files manually.On Linux or macOS (with g++ or clang++):
mkdir -p bin g++ -std=c++20 -O3 -o ./bin/runcpp runcpp/src/**/*.cc
Note: The
**glob might require a specific shell or settings. If it fails, you'll need to list the.ccfiles manually.On Windows (with MSVC):
cl.exe /std:c++latest /O2 /EHsc /Fe:./bin/runcpp.exe ./runcpp/src/**/*.cc
-
(Optional) Install
runcpp: After building, you can move the executable to a directory in your system's PATH.On Linux or macOS:
sudo mv ./bin/runcpp /usr/local/bin/
runcpp by default looks for a compile.rc file in the current directory and executes the all target.
# Runs the 'all' target from ./compile.rc
runcpp
# Runs the 'release' and 'debug' targets from ./compile.rc
runcpp release debug| Flag | Description |
|---|---|
-h, --help |
Display the help message. |
-v, --version |
Display the version of runcpp. |
-gen, --generate |
Interactively generate a basic compile.rc configuration file. |
-f, --file <path> |
Specify a configuration file to use instead of the default ./compile.rc. |
-p, --print |
Print the parsed configuration to the console before executing. Useful for debugging. |
-s, --serialize <in> |
Serialize a configuration file into a binary format. Use with -o <out> to specify the output file. |
-d, --deserialize <in> |
Execute targets from a serialized binary configuration file. |
-m, --merge <in> |
Resolve all import statements and merge configurations into a single output file. Use with -o <out>. |
-i, --init |
Start runcpp in interactive mode. |
Start an interactive runcpp session where you can run commands repeatedly.
$ runcpp --init
/> release
# Executes the release target
/> --file ./test/build.rc clean
# Executes 'clean' target from './test/build.rc'
/> --exit
$The configuration file uses a simple, target-oriented syntax.
Targets are defined with [target_name]:. Variables and commands are defined within the target. Variables can hold a single string or an array of strings.
# This is a comment
[compiler]:
# Define a variable 'cc' based on the operating system
if os == 'windows'
cc = 'cl.exe'
else
cc = 'g++'
endif
[sources]:
src_files = ['./src/main.cc', './src/utils.cc']
[release]:
# Call other targets to get their values
compiler()
sources()
# Execute a command
command = [cc()[0], '-O3', src_files(), '-o', 'myapp']Use if, else, and endif for conditional logic. The primary built-in variable is os, which can be 'windows', 'linux', 'mac', or 'unix'.
[arguments]:
if os == 'windows'
release_args = ['/std:c++latest', '/O2']
else
release_args = ['-std=c++20', '-O3', '-flto']
endifCall another target using target_name(). You can access specific elements from the returned array using index notation [index].
[output_files]:
files = ['app_release', 'app_debug']
[build_release]:
# Access the first element ('app_release') from the 'output_files' target
cmd = ['g++', '-o', output_files()[0]]Check for the existence of commands, files, or directories using depends(). The build will fail if a dependency is not found.
# Check if g++ command is available in PATH
depends('g++')
# Check if a header file exists
depends('./src/header.hh')
# Check if a directory exists
depends('./bin')Include other configuration files using import. Paths are relative to the current file.
# Import shared settings
import "./config/common.rc"
[release]:
common_args() # Target defined in common.rc
# ... release specific commandsExecute a shell command and use its standard output as a variable's value using shell().
[cflags]:
# Get compiler flags from pkg-config
flags = shell('pkg-config --cflags my-library')
[compile]:
cflags()
cmd = ['g++', flags(), 'main.cc']Contributions are welcome! Please read the CONTRIBUTING.md file for guidelines on how to report bugs, suggest enhancements, and submit pull requests.
Key rules include:
- Use C-style I/O (
printf,FILE*) instead of C++ streams. - Ensure no memory leaks are introduced.
- Format your code using the provided
.clang-formatfile.
This project is licensed under the GNU General Public License v3.0. See the LICENSE file for more details.