Skip to content
tcmakPublic

About

The modern C++23 scripting engine

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

cppsh logo

cppsh: The Modern C++23 Scripting Engine

Write C++ like it's Python or Ruby. Execute instantly, debug natively, and deploy as zero-dependency binaries.

cppsh is a lightweight, dependency-free wrapper that allows you to write modern C++23 scripts without the boilerplate. It transparently handles compilation, execution, linking, and crash handling, giving you the ergonomics of a dynamic scripting language with the blazing speed and type-safety of native C++.


πŸš€ The Problem It Solves

  • Bash is great for 10-line scripts, but becomes an unmaintainable nightmare of blacklists and string-parsing once your logic grows complex.
  • Python/Ruby have excellent ergonomics, but deploying them requires shipping massive interpreters, managing pip virtual environments, and hoping the target server has the right dependencies.
  • Standard C++ is blazingly fast and safe, but writing a simple script requires setting up CMakeLists.txt, writing int main(), and manual compiling just to test a 5-line idea.

cppsh gives you the best of all worlds: Write top-level C++ statements in a single file, run it instantly via a shebang (#!/usr/bin/env cppsh), and when you are ready for production, compile it into a single, standalone executable that runs anywhere.


✨ Features

  • Interactive REPL: Run cppsh with no arguments to launch an interactive C++ prompt with state retention and auto-printing.
  • Hot-Reloading (--watch): Perfect for web development. cppsh watches your script file and automatically recompiles and restarts your server whenever you save changes.
  • Zero Boilerplate: No int main(), no mandatory #include <iostream>. Just start writing code.
  • Shebang Support: Run your C++ files directly: ./script.cppsh
  • Ruby-Style Shell Commands: Execute OS commands trivially using backticks: `ls -la`. You can also use shell interpolation, e.g., `ls -la {dir}`.
  • Java-Like Stack Traces: If your script crashes (e.g., Segfault, Out of Bounds), cppsh automatically catches the OS signal and prints a beautiful C++23 stack trace mapped to your script's line numbers.
  • Native Debugging: Run cppsh --debug script.cppsh to drop directly into gdb or lldb. Breakpoints map exactly to your script.
  • AOT Deployment: Run cppsh --build script.cppsh to generate a heavily optimized (-O3) standalone binary.
  • Export to IDE: Run cppsh --export script.cppsh to generate a clean, standard .cpp file when your script outgrows the single-file format.
  • Magic Comments: Declare linker dependencies (// import ssl) or compiler overrides directly in your script.
  • Zero-Latency Execution: Uses SHA-1 content hashing to cache compiled binaries. If the script hasn't changed, execution is near-instant.
  • Include Hoisting: No more jumping to the top of the file. Place #include anywhere; cppsh automatically hoists them to the global scope.
  • Modern Prelude: Includes prelude.hpp aliases (str, vec, u64) for concise coding.
  • Safe Shell Escaping: Escapes special characters in variables used in shell commands to prevent injection.

πŸ› οΈ Prerequisites

Because cppsh heavily leverages bleeding-edge standard library features (like <print>, <ranges>, and <stacktrace>), you need a modern C++ compiler.

  • OS: Linux or macOS
  • Compiler: clang++ (version 18+) or g++ (version 14+)
  • Standard: C++23 support is required.

πŸ“¦ Installation

cppsh is self-contained. You just need to compile the core engine and place it in your path.

# 1. Clone the repository
git clone https://github.com/tcmak/cppsh.git
cd cppsh

# 2. Compile the engine (Requires a C++23 compiler)
# For Clang users:
clang++ -std=c++23 -O3 cppsh.cpp -o cppsh

# For GCC users (Requires g++ 14 or newer):
g++ -std=c++23 -O3 cppsh.cpp -o cppsh

# 3. Move it to your path
sudo mv cppsh /usr/local/bin/

Global Configuration (Optional)

You can configure cppsh globally via environment variables in your ~/.bashrc or ~/.zshrc:

# Set your preferred compiler (defaults to clang++ or g++)
export CXX="clang++"

# Set your preferred debugger (defaults to gdb. macOS users should use lldb)
export CPPSH_DEBUGGER="lldb"

# Global Compiler Flags (e.g., enable all warnings)
export CPPSH_CXXFLAGS="-Wall -Wextra"

# Global Linker Flags
# NOTE: cppsh defaults to '-lstdc++_libbacktrace' on Linux to provide
# Java-like stack traces when scripts crash.
# If your specific compiler/OS (e.g., custom CentOS builds, macOS) fails
# with "cannot find -lstdc++_libbacktrace", clear this variable:
export CPPSH_LDFLAGS=""

πŸ“– Quick Start

cppsh operates in two modes: Interactive REPL and Script Runner.

Mode 1: Interactive REPL

Simply type cppsh in your terminal to start experimenting with C++ instantly. Expressions are automatically evaluated and printed.

$ cppsh
=== Welcome to cppsh (C++23 REPL) ===
Type `cmd` to run a shell command.
Type exit or quit to leave.

cppsh> auto name = "Modern C++";
cppsh> name
Modern C++
cppsh> `uptime`
 14:22:15 up 2 days,  3:14,  1 user,  load average: 0.12, 0.05, 0.01
cppsh> exit

Mode 2: Script Runner

Create a file named hello.cppsh:

#!/usr/bin/env cppsh

std::println("Hello, Modern C++!");

if (args.size() > 1) {
    std::println("You passed: {}", args);
}

std::println("Current system uptime:");
`uptime`

str folder = "my documents";
`ls -la {folder}`; // Transpiles to safe, quoted: ls -la 'my documents'

Make it executable and run it:

chmod +x hello.cppsh
./hello.cppsh "Test Argument"

Mode 3: Hot-Reloading (Web Development)

If you are building a C++ web server (using a micro-framework like httplib or crow), use the watch flag. Every time you save the file, cppsh instantly recompiles and restarts the server.

cppsh --watch server.cppsh

🧠 Advanced Usage Scenarios

1. Handling Dependencies & Magic Comments

You can instruct cppsh to link against system libraries or use specific compilers just by adding comments to the top of your script.

#!/usr/bin/env cppsh
// cppsh_compiler: g++-14
// import pthread
// import ssl

std::println("This guarantees compilation with g++-14 and links libpthread and libssl.");

2. Ruby-Style Shell Commands

Any line wrapped in backticks is executed as a shell command, and its output is printed directly to stdout. Under the hood, this compiles down to a safe, memory-managed POSIX pipe.

#!/usr/bin/env cppsh
std::println("Cleaning up temp files...");
`rm -rf /tmp/cache_*`
std::println("Done.");

3. Debugging

When a script goes wrong, you don't need to manually recreate a CMake project to debug it. Just pass --debug. cppsh uses #line directives to perfectly map the compiled binary back to your original script file.

cppsh --debug my_script.cppsh

(This will launch gdb or lldb. You can type break my_script.cppsh:10 and it will work flawlessly!)

4. Deploying to Production (Standalone Binaries)

This is where cppsh destroys Python. Once your script is tested, you can compile it into a highly optimized (-O3), standalone native binary.

cppsh --build data_pipeline.cppsh

Output:

[cppsh] Successfully built optimized deployment binary: ./data_pipeline

You can now scp the ./data_pipeline executable to a server that doesn't have cppsh, clang, or any libraries installed, and it will run natively at maximum hardware speed.

5. Export to a Full C++ Project

If your script grows to thousands of lines and needs to be migrated into a proper CMake project with multiple files and headers, you don't have to rewrite it. Use the --export flag.

cppsh --export my_script.cppsh

Output:

[cppsh] Successfully exported proper C++ source to: ./my_script.cpp
        You can now open this file in your IDE (CLion, VS Code, etc.).

This generates a clean, 100% standard C++ file (my_script.cpp) in your current directory. It automatically injects the int main() boilerplate, the run_shell implementation for your backticks, and the <stacktrace> crash handlers, but intentionally strips out the #line mappings so your IDE debugger steps through the newly exported .cpp file perfectly!

6. Include Hoisting

In standard C++, you'd have to scroll to line 1 to add a header. In cppsh, you can stay in your flow. The transpiler scans for #include or import and pulls them to the global scope for you.

#!/usr/bin/env cppsh

auto start = std::chrono::steady_clock::now();

#include <chrono> // This is hoisted to the top automatically!
#include <thread>

std::this_thread::sleep_for(std::chrono::seconds(1));

7. The Modern Prelude

To make C++ feel more like a scripting language, cppsh provides a lightweight prelude of aliases and helpers. No more typing std::vector<std::string>.

#!/usr/bin/env cppsh

// 'str' and 'vec' are part of the built-in prelude
vec<str> lines = {"one", "two", "three"};

for (const auto& line : lines) {
    std::println("Processing: {}", line);
}

u64 big_num = 0xFFFFFFFFFFFFFFFF; // 'u64' alias for uint64_t

πŸ”¬ How it Works (Under the Hood)

When you run cppsh script.cppsh, the engine:

  1. Parses your script to extract #include directives and // import flags.
  2. Injects a hidden crash-handler for <stacktrace> support.
  3. Wraps your raw statements in a hidden int main(int argc, char* argv[]) block.
  4. Unpacks argv into a modern std::vector<std::string> args.
  5. Hash Check: Generates a SHA-1 hash of your script. If a matching binary exists in ~/.cache/cppsh/, it executes immediately.
  6. Transpiles `shell commands`
  • Hoists #include lines.
  • Wraps code in int main().
  • Injects Prelude and _cppsh_sh() helpers.
  1. Writes the valid C++ file to /tmp/cppsh_script.cpp.
  2. Compiles it with -O0 for near-instant startup time (or -O3 if using --build).
  3. Executes the binary and streams the output to your terminal. Replaces the engine process with the script binary using execvp.

🀝 Contributing

Contributions are welcome! Please ensure you run the lightweight, built-in test suite before submitting a PR:

# Using Clang:
clang++ -std=c++23 cppsh_test.cpp -o run_tests && ./run_tests

# Using GCC:
g++ -std=c++23 cppsh_test.cpp -o run_tests && ./run_tests

About

The modern C++23 scripting engine

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages