From 2aea1cf664188867c17909b56448056d790efe9d Mon Sep 17 00:00:00 2001 From: Luke Renaud Date: Mon, 6 Sep 2021 18:15:26 -0700 Subject: [PATCH 1/5] Forgive me Greg for I have sinned. --- .gitignore | 4 ++++ LICENSE | 24 +++++++++++++++++++ hello-world.cpp | 10 ++++++++ sheclang | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100755 hello-world.cpp create mode 100755 sheclang diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4cecca --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +hello-world +.sheclang.*.cpp +.swp* + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3c577b0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/hello-world.cpp b/hello-world.cpp new file mode 100755 index 0000000..064c2c6 --- /dev/null +++ b/hello-world.cpp @@ -0,0 +1,10 @@ +#!/usr/bin/env sheclang + +#include + +int main(int argc, char *argv[]) { + + printf("Hello World!\n"); + + return 0; +} diff --git a/sheclang b/sheclang new file mode 100755 index 0000000..8124708 --- /dev/null +++ b/sheclang @@ -0,0 +1,61 @@ +#!/bin/bash +# sheclang - shebang (#!) meets automatic clang. +# Luke Renaud +# 2021-09-06 (Public Domain) +# _____________________________________________________________________________ +# I got tired of the turnaround time when debugging my code, and I don't want +# to make a full build system or frankly even maintain a ./build.sh script for +# each project. I'm well on the road to re-inventing another build system, but +# if we can make python a simple ./.py, why can't we do the same for +# C and C++? +# +# See hello-world.cpp for the source code. Install this guy wherever your bins +# are stored, try it, weep, then rejoice that you have one less buffer open. +# +# _____________________________________________________________________________ +# LICENSE: +# Public Domain (y'all really care?) + +set -e +export IFS=$'\n' + +## Phase 1: Input Collection & Argument Checking +if [[ $# -lt 1 ]]; then + printf "sheclang requires exactly one build file arugment.\n" >&2 + exit +fi + +file_input="$1" +target_dir="$(dirname "${file_input}")" + +# TODO: Validate the extension of the output file before fucking with it. +file_input_name="$(basename "${file_input}")" +file_output="${file_input_name%.*}" +file_extension="${file_input_name##*.}" +if [[ "$file_input_name" == "$file_output" ]]; then + ( + printf "ERROR! Input and output file names match.\n" + printf " file input: %s\n" "$file_input_name" + printf " file output: %s\n" "$file_output" + ) >&2 + exit; +fi + +## Phase 2: File cleanup +# Build the copy the main source file without a hashbang line +file_input_corrected="${target_dir}/.sheclang.${file_output}.${file_extension}" +cp "${file_input}" "${file_input_corrected}" + +printf "//" | dd conv=notrunc of="${file_input_corrected}" \ + count=2 bs=1 status=none + +file_output="${target_dir}/${file_output}" + +## Phase 3: Build the file, and execute it with the remaining arguments. +shift # remove the source file from the BASH argument tree. + +# Runn my prefered build script. Customize to your tastes +clang++ -o "$file_output" "$file_input_corrected" + +# And execute with the remaining arguments +"$file_output" $* \ No newline at end of file From 459f0b41f7b505ae2ea883cbbf0ec4e581076713 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 6 Sep 2021 18:15:26 -0700 Subject: [PATCH 2/5] Forgive me Greg for I have sinned. --- .gitignore | 4 ++++ LICENSE | 24 +++++++++++++++++++ README.md | 33 ++++++++++++++++++++++++++ hello-world.cpp | 9 ++++++++ sheclang | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100755 hello-world.cpp create mode 100755 sheclang diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4cecca --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +hello-world +.sheclang.*.cpp +.swp* + diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3c577b0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..d5e56a7 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# `sheclang` - A `#!` for your C++ files. +## Installation & Test +To install, just stick the bash script in your path either by a copy or a symlink. +``` +git clone https://github.com/lrenaud/sheclang +cd sheclang +sudo cp -v sheclang /usr/bin/ +``` +To run, try the demo after installing. +``` +chmod +x ./hello-world.cpp +./hello-world.cpp +``` +## Use +1. Add the following line to the first line of your C++ file. +``` +#!/usr/bin/env sheclang +``` +2. Mark your top level `*.cpp` file as executable +``` +cd ~/your-project +chmod +x your-source-code.cpp +``` +3. Run the source file like it was an executable. Arguments passed to the `*.cpp` file will be forwarded onto the resulting binary directly. +``` +./your-source-code.cpp --your-argument positional --this-flag +``` +## Why? +Because I could. And anything that makes building performant software more +assessable to more users is worth it. I can't imagine many Python beginners are +using the debugging facilities and interactivity of the Python interactive +terminal. So why not do what I can to make building C++ as trivial to get +off the ground as trivial python. \ No newline at end of file diff --git a/hello-world.cpp b/hello-world.cpp new file mode 100755 index 0000000..cb666fe --- /dev/null +++ b/hello-world.cpp @@ -0,0 +1,9 @@ +#!/usr/bin/env sheclang +#include + +int main(int argc, char *argv[]) { + + printf("Hello World!\n"); + + return 0; +} diff --git a/sheclang b/sheclang new file mode 100755 index 0000000..8124708 --- /dev/null +++ b/sheclang @@ -0,0 +1,61 @@ +#!/bin/bash +# sheclang - shebang (#!) meets automatic clang. +# Luke Renaud +# 2021-09-06 (Public Domain) +# _____________________________________________________________________________ +# I got tired of the turnaround time when debugging my code, and I don't want +# to make a full build system or frankly even maintain a ./build.sh script for +# each project. I'm well on the road to re-inventing another build system, but +# if we can make python a simple ./.py, why can't we do the same for +# C and C++? +# +# See hello-world.cpp for the source code. Install this guy wherever your bins +# are stored, try it, weep, then rejoice that you have one less buffer open. +# +# _____________________________________________________________________________ +# LICENSE: +# Public Domain (y'all really care?) + +set -e +export IFS=$'\n' + +## Phase 1: Input Collection & Argument Checking +if [[ $# -lt 1 ]]; then + printf "sheclang requires exactly one build file arugment.\n" >&2 + exit +fi + +file_input="$1" +target_dir="$(dirname "${file_input}")" + +# TODO: Validate the extension of the output file before fucking with it. +file_input_name="$(basename "${file_input}")" +file_output="${file_input_name%.*}" +file_extension="${file_input_name##*.}" +if [[ "$file_input_name" == "$file_output" ]]; then + ( + printf "ERROR! Input and output file names match.\n" + printf " file input: %s\n" "$file_input_name" + printf " file output: %s\n" "$file_output" + ) >&2 + exit; +fi + +## Phase 2: File cleanup +# Build the copy the main source file without a hashbang line +file_input_corrected="${target_dir}/.sheclang.${file_output}.${file_extension}" +cp "${file_input}" "${file_input_corrected}" + +printf "//" | dd conv=notrunc of="${file_input_corrected}" \ + count=2 bs=1 status=none + +file_output="${target_dir}/${file_output}" + +## Phase 3: Build the file, and execute it with the remaining arguments. +shift # remove the source file from the BASH argument tree. + +# Runn my prefered build script. Customize to your tastes +clang++ -o "$file_output" "$file_input_corrected" + +# And execute with the remaining arguments +"$file_output" $* \ No newline at end of file From 16595fcd89e321b894ace5a40f5bf526004e19ce Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 10 Jun 2023 16:07:38 -0700 Subject: [PATCH 3/5] forgot some legacy cleanup --- sheclang | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/sheclang b/sheclang index 8124708..5b2321a 100755 --- a/sheclang +++ b/sheclang @@ -17,7 +17,11 @@ # Public Domain (y'all really care?) set -e -export IFS=$'\n' +#O_IFS=${IFS} +#export IFS=$'\n' + +COMPILER="clang++" +BUILD_FLAGS=() ## Phase 1: Input Collection & Argument Checking if [[ $# -lt 1 ]]; then @@ -25,6 +29,21 @@ if [[ $# -lt 1 ]]; then exit fi +# Load a global configuartion for a user +if [[ -e $HOME/.config/sheclang/config ]]; then + source $HOME/.config/sheclang/config +elif [[ -e $HOME/.sheclang ]]; then + source $HOME/.sheclang +fi + +# Load a project specific config +if [[ -e $PWD/sheclang.conf ]]; then + source $PWD/sheclang.conf +elif [[ -e $PWD/.sheclang ]]; then + source $PWD/.sheclang +fi +#echo ${BUILD_FLAGS[@]} + file_input="$1" target_dir="$(dirname "${file_input}")" @@ -55,7 +74,8 @@ file_output="${target_dir}/${file_output}" shift # remove the source file from the BASH argument tree. # Runn my prefered build script. Customize to your tastes -clang++ -o "$file_output" "$file_input_corrected" +#$COMPILER ${BUILD_FLAGS[@]} -o "$file_output" "$file_input_corrected" +$COMPILER -o "$file_output" "$file_input_corrected" ${BUILD_FLAGS[@]} # And execute with the remaining arguments -"$file_output" $* \ No newline at end of file +"$file_output" $* From 0a2c17740af7da2e69cf38111bccb1f6ba5953b5 Mon Sep 17 00:00:00 2001 From: Luke Date: Mon, 24 Jul 2023 15:10:49 -0700 Subject: [PATCH 4/5] updated to allow for #! arguments --- README.md | 27 ++++++++++- hello-world.cpp | 2 +- sheclang | 121 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 136 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index d5e56a7..915037c 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ chmod +x ./hello-world.cpp ./hello-world.cpp ``` ## Use +### Basic Use 1. Add the following line to the first line of your C++ file. ``` #!/usr/bin/env sheclang @@ -25,9 +26,33 @@ chmod +x your-source-code.cpp ``` ./your-source-code.cpp --your-argument positional --this-flag ``` +### Advanced Use + - Use the `env -S` seperator to pass build arguments directly into `sheclang`. + - `sheclang` looks for the `--` as a seperator when invoked in this way to identify the arguments intended for the compiler verses arguments intended for your executable. If you do not want to have to play the game of complexities in the invocation here, consider using an environmental config to override the Magic Variables instead. + - example: `#!/usr/bin/env -S sheclang -lm --` to pass the `-lm` flag directly to the compiler. + - Use a `~/.config`, `~/.sheclang`, or local `sheclang.conf` to add compiler arguments + - `sheclang` will look for files the following order, and simply source the contents of the files prior to doing any file processing, compiling, or executing. + 1. `$HOME/.config/sheclang/config` + 2. `$HOME/.sheclang` + 3. `$PWD/sheclang.conf` + 4. `$PWD/.sheclang` + - If you want to override the configuration of a previous script, uses a higher numbered (later loaded) script to set the final configuration prior to the build process. For arugments you can override, look at the Magic Variables List section. + +### Magic Variables List +The following variables are used internally by sheclang, and can be overriden by a sourced script as defined in the advanced usage. + +| Variable | Default | Description | +| --- | --- | --- | +| `COMPILER` | clang++ | The compiler called by sheclang | +| `SHECLANG_VERBOSE` | false | When `true`, report information about the execution process for debugging | +| `POST_BUILD_FLAGS` | *empty array* | an array of flags to pass to `$COMPILER` at build time. | +| `PRE_BUILD_FLAGS` | *empty array* | an array of flags to pass to `$COMPILER` prior to the source code file. These are post-merged with arguments that are pased via an advanced `!#` call per the Advanced Use section above. | +| `RUNTIME ARGS` | *empty array* | Arguments passed to your executable. Automatically merged with things you pass when invoking the script. These arguments are placed before arguments passed via the CLI. | + ## Why? Because I could. And anything that makes building performant software more assessable to more users is worth it. I can't imagine many Python beginners are using the debugging facilities and interactivity of the Python interactive terminal. So why not do what I can to make building C++ as trivial to get -off the ground as trivial python. \ No newline at end of file +off the ground as trivial python. I detest build systems, and I just want my tools +to work. diff --git a/hello-world.cpp b/hello-world.cpp index cb666fe..57cb1fe 100755 --- a/hello-world.cpp +++ b/hello-world.cpp @@ -1,4 +1,4 @@ -#!/usr/bin/env sheclang +#!/usr/bin/env -S sheclang #include int main(int argc, char *argv[]) { diff --git a/sheclang b/sheclang index 5b2321a..90b5ba6 100755 --- a/sheclang +++ b/sheclang @@ -1,6 +1,5 @@ #!/bin/bash # sheclang - shebang (#!) meets automatic clang. -# Luke Renaud # 2021-09-06 (Public Domain) # _____________________________________________________________________________ # I got tired of the turnaround time when debugging my code, and I don't want @@ -13,21 +12,62 @@ # are stored, try it, weep, then rejoice that you have one less buffer open. # # _____________________________________________________________________________ +# Version History: +# 2023-07-24 - Updated to accept !# arguments seperated by -- +# 2021-09-06 - Initial Release +# _____________________________________________________________________________ # LICENSE: -# Public Domain (y'all really care?) +# Public Domain + +function __sheclang_version() { +SHECLANG_VERSION="2023-07-24" +SV_LEN___="$SHECLANG_VERSION" +printf "" +printf "\e[4msheclang\e[0m: a she-bang (#!) for your C/C++ files.\n" +printf "\e[4mversion\e[0m: $SV_LEN___\n" +tput sgr0 +} +function __sheclang_usage() { +SHECLANG_VERSION="2023-07-24" +cat << EOF +usage: + 1. add "#!/usr/bin/env shebang" to your main C/C++ file, + 2. mark the file as executable + 3. try to execute it. + 4. Profit. + +For advanced usage information, see the project README file. +EOF +} set -e #O_IFS=${IFS} -#export IFS=$'\n' +export IFS=$'\n' COMPILER="clang++" -BUILD_FLAGS=() +SHECLANG_VERBOSE=${SHECLANG_VERBOSE:-false} +################### ## Phase 1: Input Collection & Argument Checking if [[ $# -lt 1 ]]; then - printf "sheclang requires exactly one build file arugment.\n" >&2 + printf "sheclang requires at least the build file arugment.\n" >&2 + __sheclang_usage exit fi +case "$1" in + -v|-V|--version) + __sheclang_version + exit + ;; + --help|-h) + __sheclang_version + __sheclang_usage + exit + ;; + *) + ;; +esac + # Load a global configuartion for a user if [[ -e $HOME/.config/sheclang/config ]]; then @@ -42,9 +82,47 @@ if [[ -e $PWD/sheclang.conf ]]; then elif [[ -e $PWD/.sheclang ]]; then source $PWD/.sheclang fi -#echo ${BUILD_FLAGS[@]} -file_input="$1" +# Collect arguments from command line +# First check to see if we have a -- indicating a split between arguments for clang and arguments for the tool itself +CLI_CC_ARGS=() +CLI_BIN_ARGS=() +FOUND_SPLIT=false +for ARG in $@; do + if [[ "$ARG" == "--" ]]; then + FOUND_SPLIT=true + continue + fi + + if [[ "$FOUND_SPLIT" == "true" ]]; then + CLI_BIN_ARGS+=("$ARG") + else + CLI_CC_ARGS+=("$ARG") + fi +done + +# If we never found the -- seperator, then all of the arguments are assumed to have been +# input arguments +if [[ "$FOUND_SPLIT" == "false" ]]; then + CLI_BIN_ARGS+=(${CLI_CC_ARGS[@]}) + unset CLI_CC_ARGS +fi + +# Next, remove the source code file as the root executable +file_input="${CLI_BIN_ARGS[0]}" +# and validate that the file is indeed a source code file, with a sane extension +if [[ ! -f "$file_input" ]]; then + printf "ERROR: provided input file could not be found.\n" + printf " INFO: sheclang effective invocation:\n " + printf "%s " $0 ${CLI_CC_ARGS[@]} -- "${CLI_BIN_ARGS[@]}" + printf "\n" + exit 1 +elif [[ "$SHECLANG_VERBOSE" == true ]]; then + printf " INFO: sheclang effective invocation:\n " + printf "%s " $0 ${CLI_CC_ARGS[@]} -- "${CLI_BIN_ARGS[@]}" + printf "\n" +fi + target_dir="$(dirname "${file_input}")" # TODO: Validate the extension of the output file before fucking with it. @@ -60,22 +138,41 @@ if [[ "$file_input_name" == "$file_output" ]]; then exit; fi +################### ## Phase 2: File cleanup # Build the copy the main source file without a hashbang line file_input_corrected="${target_dir}/.sheclang.${file_output}.${file_extension}" cp "${file_input}" "${file_input_corrected}" +# Convert the shebang into a comment line so the compiler doesn't see it printf "//" | dd conv=notrunc of="${file_input_corrected}" \ count=2 bs=1 status=none file_output="${target_dir}/${file_output}" +################### ## Phase 3: Build the file, and execute it with the remaining arguments. -shift # remove the source file from the BASH argument tree. +unset 'CLI_BIN_ARGS[0]' # remove the source file from the BASH argument tree. -# Runn my prefered build script. Customize to your tastes -#$COMPILER ${BUILD_FLAGS[@]} -o "$file_output" "$file_input_corrected" -$COMPILER -o "$file_output" "$file_input_corrected" ${BUILD_FLAGS[@]} + +# Finally, merge the CLI build arguments with the pre-defined arguments +PRE_BUILD_FLAGS+=(${CLI_CC_ARGS[@]}) +#POST_BUILD_FLAGS are defined in scripts only +RUNTIME_ARGS+=(${CLI_BIN_ARGS[@]}) + +# Run my prefered build script. Customize to your tastes +#$COMPILER ${PRE_BUILD_FLAGS[@]} -o "$file_output" "$file_input_corrected" +if [[ "$SHECLANG_VERBOSE" == true ]]; then + printf " INFO: sheclang effective compiler invocation:\n " + printf "%s " $COMPILER ${PRE_BUILD_FLAGS[@]} -o "$file_output" "$file_input_corrected" ${POST_BUILD_FLAGS[@]} + printf "\n" +fi +$COMPILER ${PRE_BUILD_FLAGS[@]} -o "$file_output" "$file_input_corrected" ${POST_BUILD_FLAGS[@]} # And execute with the remaining arguments -"$file_output" $* +if [[ "$SHECLANG_VERBOSE" == true ]]; then + printf " INFO: sheclang effective binary invocation:\n " + printf "%s " "$file_output" ${RUNTIME_ARGS[@]} + printf "\n" +fi +"$file_output" ${RUNTIME_ARGS[@]} From 4389acc654918559863976da1d7f44c01dbb0542 Mon Sep 17 00:00:00 2001 From: Luke Date: Sat, 7 Oct 2023 11:57:37 -0700 Subject: [PATCH 5/5] tweak upstream url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 915037c..5cf3b41 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Installation & Test To install, just stick the bash script in your path either by a copy or a symlink. ``` -git clone https://github.com/lrenaud/sheclang +git clone https://github.com/opensiriusfox/sheclang cd sheclang sudo cp -v sheclang /usr/bin/ ```