///bin/true;COMPILER_OPTIONS="-g -Wall -Wextra --std=c99 -O1 -fsanitize=address,undefined";THIS_FILE="$(cd "$(dirname "$0")"; pwd -P)/$(basename "$0")";OUT_FILE="/tmp/build-cache/$THIS_FILE";mkdir -p "$(dirname "$OUT_FILE")";test "$THIS_FILE" -ot "$OUT_FILE" || $(which clang || which gcc) $COMPILER_OPTIONS -xc "$THIS_FILE" -o "$OUT_FILE" || exit;exec "$OUT_FILE" "$@" | |
#include <stdio.h> | |
int main() { | |
printf("Hello world!\n"); | |
return 0; | |
} |
///bin/true;COMPILER_OPTIONS="-g -Wall -Wextra --std=c++14 -O1 -fsanitize=address,undefined";THIS_FILE="$(cd "$(dirname "$0")"; pwd -P)/$(basename "$0")";OUT_FILE="/tmp/build-cache/$THIS_FILE";mkdir -p "$(dirname "$OUT_FILE")";test "$THIS_FILE" -ot "$OUT_FILE" || $(which clang++ || which g++) -xc++ $COMPILER_OPTIONS "$THIS_FILE" -o "$OUT_FILE" || exit;exec "$OUT_FILE" "$@" | |
#include <iostream> | |
int main() { | |
std::cerr << "Hello, world!" << std::endl; | |
return 0; | |
} |
#!/bin/bash | |
///bin/true;COMPILER_OPTIONS="-g -Wall -Wextra --std=c99 -O1 -fsanitize=address,undefined";THIS_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd -P)/$(basename "${BASH_SOURCE[0]}")";OUT_FILE="/tmp/build-cache/$THIS_FILE";mkdir -p "$(dirname "$OUT_FILE")";test "$THIS_FILE" -ot "$OUT_FILE" || tail -c +12 "$0" | $(which clang || which gcc) -xc $COMPILER_OPTIONS -o "$OUT_FILE" - || exit $?;exec -a "$0" "$OUT_FILE" "$@" | |
#include <stdio.h> | |
int main() { | |
printf("Hello world!\n"); | |
return 0; | |
} |
#!/bin/bash | |
///bin/true;COMPILER_OPTIONS="-g -Wall -Wextra --std=c++14 -O1 -fsanitize=address,undefined";THIS_FILE="$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd -P)/$(basename "${BASH_SOURCE[0]}")";OUT_FILE="/tmp/build-cache/$THIS_FILE";mkdir -p "$(dirname "$OUT_FILE")";test "$THIS_FILE" -ot "$OUT_FILE" || tail -c +12 "$0" | $(which clang++ || which g++) -xc++ $COMPILER_OPTIONS -o "$OUT_FILE" - || exit $?;exec -a "$0" "$OUT_FILE" "$@" | |
#include <iostream> | |
int main() { | |
std::cerr << "Hello, world!" << std::endl; | |
return 0; | |
} |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Here is my approach, also allowing for argv to be populated arbitrarily: |
This comment has been minimized.
This comment has been minimized.
Alternatively: //usr/bin/cc -o ${o=`mktemp`} "$0" && exec -a "$0" "$o" "$@"
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("%s", argv[0]);
for (int i = 1; i < argc; i++)
printf(" %s", argv[i]);
printf("\n");
return 0;
} |
This comment has been minimized.
This comment has been minimized.
Fun stuff! Here's yet another way: ///usr/bin/env make ${0%%.cpp} CXXFLAGS="-g -Wall -Wextra -std=c++14 -O1" && exec ./${0%%.cpp}
#include <iostream>
int main() {
std::cerr << "Hello, world!" << std::endl;
return 0;
} |
This comment has been minimized.
This comment has been minimized.
long ago I found this somewhere. Compiles only if there is a change.
|
This comment has been minimized.
This comment has been minimized.
This is so dirty I would never tolerate it in a source tree of mine, but its still a nice hack. |
This comment has been minimized.
This comment has been minimized.
I would be surprised if any of these that don’t have Edit: I just realized that this behaviour of running a file as a shell script if it’s not otherwise executable is a special behaviour of
Still, you probably don’t want to rely on your caller calling the right exec*() variant for the shebang-less files to work (which, incidentally, both I learned something. Thanks. |
This comment has been minimized.
This comment has been minimized.
And to add something constructive to this thread: #!/usr/bin/tcc -run |
This comment has been minimized.
This comment has been minimized.
Thank you for this <3 |
This comment has been minimized.
This comment has been minimized.
These won't work on Mac because |
This comment has been minimized.
This comment has been minimized.
|
This comment has been minimized.
This comment has been minimized.
what's apply scenarios? |
This comment has been minimized.
This comment has been minimized.
nice hack, and fun, but just fun |
This comment has been minimized.
This comment has been minimized.
And Perl? #ifndef C
$_=$0,s/\.c$//,print`gcc -DC -o $_ $0 && ./$_; rm -f $_`;
__END__
#endif
#include <stdio.h>
int main() {
puts("Hello World!");
return 0;
} |
This comment has been minimized.
This comment has been minimized.
//usr/bin/env clang++ $0 -o ${o=`mktemp`} && exec $o $*
#include <stdio.h>
int main() {
printf("Hello World!\n");
return 0;
} |
This comment has been minimized.
Forget having a build system. Just chmod +x your source code!
There are 4 varieties here: C vs C++, and shebang vs no shebang.
The shebang/no shebang versions have different minor advantages and disadvantages. The no shebang version is a true one-liner, and the file remains completely valid C that can be compiled in the normal way in addition to the direct execution way. It also doesn't require bash to be installed; any shell should work. However, it can't be executed with execve, or with the shell's "source" built-in command, and it doesn't forward argv[0] to the C binary.
The shebang version isn't valid C, so the file can only be compiled by directly executing it (which strips the shebang). It also requires bash explicitly. On the plus side, it can be executed with execve like a real binary, and with the shell's "source" built-in command. Plus, it correctly sets argv[0] when calling the C binary.
All versions accept an unlimited number of arguments correctly, cache the compiled binary, and work with both GCC and Clang. They should work on most Unix varieties including most Linux distros, macOS, and various BSDs. Windows users are out of luck (although you could try using Cywgin, MinGW, or WSL).