A shebang-friendly script for "interpreting" single C99, C11, and C++ files, including rcfile support.

Related tags

Utilities c99sh
Overview

c99sh

Basic Idea

A shebang-friendly script for "interpreting" single C99, C11, and C++ files, including rcfile support. Build Status

For example, installing this ~/.c99shrc control file

-Wall -g -O2
#include <stdio.h>

permits executing hello containing

#!/usr/bin/env c99sh
int main()
{
    puts("Hello, world!");
}

to produce the output one expects provided c99sh is in the path. You may also run c99sh foo.c to execute some foo.c lacking the shebang line. Try c99sh -v foo.c if you encounter trouble and want to see the compilation command. Check out c99sh -h for all the command line options you might use. In particular, for simple tasks you might find that the command line options in conjunction with HERE documents can accomplish many things. For example,

$ ./c99sh -sm <<HERE
puts("Hello, world!");
HERE

One or more lines can be included using -e:

$ ./c99sh -e 'int main()' -e '{}'

Usually, -sm appears alongside -e:

$ ../c99sh -e 'int start = 3;' -sm <<HERE
if (start == 3) {
    printf("Hello from 1-liner\n");
} else {
    return 1;
}
HERE

Beware quote escaping for -e could use some printf love. Patches welcome.

Control Files

Control files can supply compilation and linking flags, preprocessor directives like #include, and pkg-config directives to simplify library usage. A c99shrc located in the same directory as the interpreted source will be used. Otherwise a ~/.c99shrc is processed if available. See c99shrc.example for an extended control file enabling GSL, GLib, and SQLite capabilities. Control files ease accessing libraries with higher-level data structures.

A more entertaining example is an OpenMP-enabled Monte Carlo computation of ฯ€ screaming like a banshee on all your cores (c99shrc, source):

#!/usr/bin/env c99sh

int main(int argc, char *argv[])
{
    long long niter = argc > 1 ? atof(argv[1]) : 100000;
    long long count = 0;

    #pragma omp parallel
    {
        unsigned int seed = omp_get_thread_num();

        #pragma omp for reduction(+: count) schedule(static)
        for (long long i = 0; i < niter; ++i) {
            const double x = rand_r(&seed) / (double) RAND_MAX;
            const double y = rand_r(&seed) / (double) RAND_MAX;
            count += sqrt(x*x + y*y) < 1;
        }

    }

    printf("%lld: %g\n", niter, M_PI - 4*(count / (double) niter));
}

Take that, GIL.

Kidding aside, the speedup in the edit-compile-run loop can be handy during prototyping or analysis. It is nice when useful one-off scripts can be moved directly into C ABI code instead of requiring an additional {Python,Octave,R}-to-C translation and debugging phase. For example, compare the Octave version of some simple logic with the equivalent c99sh-based version requiring only a few one-time additions to your ~/.c99shrc.

Shebang Tricks

Dual shebang/compiled support, that is a source file that can be both interpreted via ./shebang.c and compiled via gcc shebang.c, can most succinctly be achieved as follows:

#if 0
exec c99sh "$0" "[email protected]"
#endif

#include <stdio.h>

int main(int argc, char *argv[])
{
    for (int i = 1; i < argc; ++i) {
        printf("Hello, %s!\n", argv[i]);
    }
}

This dual shebang approach permits quick testing/iteration on valid C source files using the -t option:

#if 0
exec c99sh -t 'test()' "$0" "[email protected]"
#endif

#include <stdio.h>

int logic()
{
    return 42;
}

static void test()
{
    printf("%d\n", logic());
}

Testing in this manner resembles how folks use Python's __main__ inside libraries.

C++

As nearly the entire C99-oriented implementation works for C++, by invoking c99sh through either a copy or symlink named cxxsh, you can write C++-based logic. The relevant control files are named like cxxshrc in this case and they support directives like using namespace std and namespace fb = foo::bar. See cxx/hello and cxx/cxxshrc for a hello world C++ example. See cxx/shebang.cpp and cxx/quicktest.cpp for C++ dual shebang/compiled idioms.

One nice use case is hacking atop Eigen since it provides pkg-config support. That is, cxxsh -p eigen3 myprogram builds and runs a one-off, Eigen-based program. With the right cxxshrc, such a program can be turned into a script. Though, you will likely notice the compilation overhead much moreso with C++ than C99. That said, for repeated invocation an output binary can be saved with the -x option should repeated recompilation be prohibitively expensive.

C11

C11 can be used via a symlink named c11sh with control files like c11shrc.

Credits

The idea for c99sh came from 21st Century C's section "Compiling C Programs via Here Document" (available online) by Ben Klemens. Additionally, I wrote it somewhat in reaction to browsing the C++-ish work by elsamuko/cppsh.

The dual shebang/compiled approach was suggested by mcandre and jtsagata. Thank you both for pushing on the idea, as I did not think it could be done in three clean lines.

The one line execution similar to Perl's -e is done by mattapiroglu.

The -l command line option was contributed by flipcoder.

Comments
  • Support dual shebang/compiled behavior

    Support dual shebang/compiled behavior

    Is there another way to write the shebang line #!/usr/bin/env c99sh, so that a .c file supports both c99sh invocation, as well as traditional gcc compilation? I think this shebang would be rejected by most C compilers?

    opened by mcandre 14
  • Added an option for one-line statements

    Added an option for one-line statements

    Previous attempt didn't include tests. Here I try again:

    This is what I wanted to do: c99sh -s 'printf("hi\n");'

    and I wasn't sure if it was already possible, so I updated the script. If it was already possible, maybe the README can be updated with an example, or if not maybe we can add it like this or another way?

    Motive: Why would you want to run a one-line statement? I haven't put it into action yet, but I believe it'll be useful in pipelining, for example possibly using c instead of sed or awk (if one has necessary libs/functions).

    I wasn't sure if I should be updating any tests, and I'm not an expert on bash scripting, so hopefully I've done it right. And here it is.

    opened by albuspiroglu 3
  • bash: unbound var

    bash: unbound var "pkg"

    1> bash c99sh c99sh: line 126: pkg: unbound variable

    1> bash --version GNU bash, Version 4.3.30(1)-release (x86_64-pc-linux-gnu) (Debian Jessie)

    opened by Patterner 3
  • Possibly fire up compiler early to amortize load time

    Possibly fire up compiler early to amortize load time

    Might be possible to bring up the compiler early, in the background, against a named pipe. This would let the OS do its thing for the compiler while we're out hitting RC files and pkg-config. Small chance it'll improve latency.

    opened by RhysU 3
  • Problems with non-RC #includes?

    Problems with non-RC #includes?

    Seeing repeated include issues with a script like the following:

    #!/home/rhys/bin/cxxsh -m
    #include <random>
    using namespace std;
    

    which should compile without incident. Problem may be for any include not in an RC file, but I've not tracked it down.

    opened by RhysU 1
  • 1-liner: multiple -e statements should be saved as separate lines

    1-liner: multiple -e statements should be saved as separate lines

    Previous version didn't do it, becase the bash script loop I tried earlier separated every white space in the statement array and I had resorted to save the whole array in one echo.

    After encountering the problem on multiple statements with a #define (or // comment-line), I learned how to fix it with a proper loop.

    opened by albuspiroglu 0
  • Added an option for one-line statements

    Added an option for one-line statements

    This is what I wanted to do: c99sh -ms1 'printf("hi\n");'

    and I wasn't sure if it was already possible, so I added an option to the script. If it's already possible, maybe the README can be updated with an example, or if not maybe we can add it?

    Motive: Why would you want to run a one-line statement? I haven't put it into action yet, but I believe it'll be useful in pipelining, for example possibly using c instead of sed or awk (if one has necessary libs/functions).

    I wasn't sure if I should be updating any tests, and I'm not an expert on bash scripting, so hopefully I've done it right. And here it is.

    opened by albuspiroglu 0
  • stdin not handled properly

    stdin not handled properly

    Turns out this doesn't read from stdin when run...

    #!/home/rhys/bin/c99sh -sm
    
    char name[255] = "Oxford";
    int age = 8;
    
    puts("What's your name?");
    scanf("%s", name);
    puts("What's your birthday?");
    printf("Hello, %s. You are %d years old.\n", name, age);
    
    opened by RhysU 0
  • Add a -Wall -Werror command line flag

    Add a -Wall -Werror command line flag

    Would aid having small, clean scripts to have a single flag enact -Wall -Werror. Maybe worth separating the two. Certainly something possible in an RCfile.

    opened by RhysU 0
Owner
Rhys Ulerich
Rhys Ulerich
A cross platform C99 library to get cpu features at runtime.

cpu_features A cross-platform C library to retrieve CPU features (such as available instructions) at runtime. Table of Contents Design Rationale Code

Google 2.1k Oct 6, 2022
A bullet-hell shooter game made in C99 for my college project.

Kosmos A bullet-hell shooter game made in C99 for my college project. Building Linux Install requied libraries Ubuntu sudo apt install libasound2-dev

Siddharth Roy 18 Sep 20, 2022
Sqrt OS is a simulation of an OS scheduler and memory manager using different scheduling algorithms including Highest Priority First (non-preemptive), Shortest Remaining Time Next, and Round Robin.

A CPU scheduler determines an order for the execution of its scheduled processes; it decides which process will run according to a certain data structure that keeps track of the processes in the system and their status. A process, upon creation, has one of the three states: Running, Ready, Blocked (doing I/O, using other resources than CPU or waiting on unavailable resource).

Abdallah Hemdan 18 Apr 15, 2022
WhyNotWin11 - Detection Script to help identify why your PC isn't Windows 11 ready

Detection Script to help identify why your PC isn't Windows 11 ready

Robert C. Maehl 5.9k Oct 2, 2022
RapidObj is an easy-to-use, single-header C++17 library that loads and parses Wavefront .obj files.

RapidObj About Integration Prerequisites Manual Integration CMake Integration API RapidObj Result Next Steps OS Support Third Party Tools and Resource

Slobodan Pavlic 100 Sep 28, 2022
Your friendly e-mail address validation library.

libvldmail Your friendly e-mail address validation library. Why? Did you know that parentheses, spaces and - according to the RFC 6531 document - emoj

Cthulhux 46 Sep 9, 2022
fpicker is a Frida-based fuzzing suite supporting various modes (including AFL++ in-process fuzzing)

fpicker fpicker is a Frida-based fuzzing suite that offers a variety of fuzzing modes for in-process fuzzing, such as an AFL++ mode or a passive traci

Dennis Heinze 182 Sep 27, 2022
A small and portable INI file library with read/write support

minIni minIni is a portable and configurable library for reading and writing ".INI" files. At just below 900 lines of commented source code, minIni tr

Thiadmer Riemersma 277 Sep 23, 2022
This project aims to facilitate debugging a kernel driver in windows by adding support for a code change on the fly without reboot/unload, and more!

BSOD Survivor Tired of always telling yourself when you got a BSOD that what if I could just return to the caller function which caused the BSOD, and

Ido Westler 156 Oct 1, 2022
The goal of arrowvctrs is to wrap the Arrow Data C API and Arrow Stream C API to provide lightweight Arrow support for R packages

The goal of arrowvctrs is to wrap the Arrow Data C API and Arrow Stream C API to provide lightweight Arrow support for R packages to consume and produce streams of data in Arrow format. Right now itโ€™s just a fun way for me to learn about Arrow!

Dewey Dunnington 30 Aug 5, 2022
A tool for use with clang to analyze #includes in C and C++ source files

Include What You Use For more in-depth documentation, see docs. Instructions for Users "Include what you use" means this: for every symbol (type, func

null 3k Sep 28, 2022
ByteCopy , or BCP, intends to copy files accurately (down to the bytes) in a simple , safe and efficient manner.

ByteCopy v3.6 About ByteCopy , or BCP, intends to copy files accurately (down to the bytes) in a simple , safe and efficient manner. It's functionalit

A.P. Jo. 16 Jun 22, 2022
This is a collection of tools for creating and manipulating BitTorrent v2 torrent files

torrent tools This is a collection of tools for creating and manipulating BitTorrent v2 torrent files. torrent-new can create hybrid torrents, but the

Arvid Norberg 8 Jun 1, 2022
libnpy is a simple C++ library for reading and writing of numpy's .npy files.

C++ library for reading and writing of numpy's .npy files

Leon Merten Lohse 178 Sep 29, 2022
CE-Plugin - ๐Ÿ“ƒ Support Version Cheat Engine 6.5~Higher

?? Support Version Cheat Engine 6.5~Higher ?? Preview โ„๏ธ Reference & Thanks Cheat Engine[Debugger with plugin] Unicorn[CPU emulator framework] Capston

kanren3 1 Jul 25, 2022
GNU project's implementation of the standard C library(with Xuantie RISC-V CPU support).

GNU project's implementation of the standard C library(with Xuantie RISC-V CPU support).

T-Head Semiconductor Co., Ltd. 5 Mar 17, 2022
This library support run-time type casting faster than dynamic_cast ( similar to unreal engine's CastTo )

Fast Runtime Type Casting This library give you C++ Fast Runtime Type Casting faster than dynamic_cast ( similar to Unreal Engine's CastTo, IsChildOf

SungJinKang 7 Jun 11, 2022
Dead simple C logging library contained in a single header (.h) file

Seethe Logging so simple, you only need to include a single header file. seethe supports 6 different log levels (DEBUG, INFO, NOTICE, WARNING, ERROR,

Jason Nguyen 27 May 9, 2022
GPU Task Spooler - A SLURM alternative/job scheduler for a single simulation machine

GPU Task Spooler - A SLURM alternative/job scheduler for a single simulation machine

Duc Nguyen 86 Oct 1, 2022