Skip to content

Instantly share code, notes, and snippets.

@garettbass
Last active August 6, 2019 12:08
Show Gist options
  • Save garettbass/ae8b458577c54a4993996eed1687688d to your computer and use it in GitHub Desktop.
Save garettbass/ae8b458577c54a4993996eed1687688d to your computer and use it in GitHub Desktop.
Self-executable C++ file
///usr/bin/env \
[ -n "${PATHEXT}" ] && ext='.exe'; \
bin="$(dirname $0)/$(basename ${0%.*})$ext"; \
c++ -std=c++11 -Werror -o $bin $0 \
&& $bin "$@"; \
status=$?; \
rm $bin; \
exit $status
#include <cstdio>
int main(int argc, char** argv) {
for (int i = 0; i < argc; ++i) {
printf("argv[%i]: \"%s\"\n",i,argv[i]);
}
return 0;
}
@garettbass
Copy link
Author

garettbass commented Jul 14, 2018

you can use chmod +x main.cpp to make your program directly runnable on *nix, or sh main.cpp in a terminal. I use this header to edit/compile/run the same C/C++ code on macOS and Windows (via gitbash)

@garettbass
Copy link
Author

garettbass commented Sep 1, 2018

I updated the header to determine the correct file extension for the executable, .exe for windows (where the environment should have $PATHEXT), and no extension for Unix-like environments.

Here is an overview of each line of the header:

///usr/bin/env \

  • This line is similar to a shebang, #!/user/bin/env, that you might find in a shell, python, ruby, etc. script, and ends with a line continuation, \, so that the next few lines can combine into one long shell command. The shell interprets /// the same as a single slash, and the C/C++ compiler interprets the first two slashes as a single-line comment. The line continuations at the end of each line of the header enable that single line comment to extend over multiple lines, making the various stages of the script more readable than they would be on a single long line.

[ -n "${PATHEXT}" ] && ext='.exe'; \

  • This line checks whether the $PATHEXT environment variable is non-empty, and if so sets the ext variable to contain the string '.exe'. The $PATHEXT environment variable is generally only present on Windows systems, to my knowledge, and is used as a convenient check that we need to compile an executable ending with the .exe file extension.

bin="$(dirname $0)/$(basename ${0%.*})$ext"; \

  • This sets the variable bin to contain a directory-qualified path to the compiled executable. The rest of the command will use $bin to refer to the compiled executable.

c++ -std=c++11 -Werror -o $bin $0 \

  • This line invokes the C++ compiler to compile $0, the input file, to produce the executable $bin. You can customize the compiler invocation as needed. I generally add include directories and such on additional lines with line continuations. To compile C instead, change this line to: cc -std=c11 -Werror -o $bin $0 \

&& $bin "$@"; \

  • This line executes the compiled executable, $bin if the compilation succeeded, and passes all of the remaining command line arguments, "$@" to the compiled executable.

status=$?; \

  • This line stores the status resulting from the attempt to compile and execute the program.

rm $bin; \

  • This line deletes the compile binary after running the program.

exit $status

  • This line exits the shell script interpreter, so that the rest of the C++ file will not be interpreted as shell script.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment