3 ms·
You can already do this without using binfmt ... #if 0 gcc "$0" -o "$@".out && exec ./"$@".out #endif #include <stdio.h> int main () { printf ("hello
by rwmj 1y ago
You can already do this without using binfmt ...
#if 0
gcc "$0" -o "$@".out && exec ./"$@".out
#endif
#include <stdio.h>
int main () { printf ("hello, world\n"); return 0; }
Usage:
$ chmod +x print.c
$ ./print.c
hello, world
(Could be better to use a temporary file though.)
There's a similar cute trick for compiled OCaml scripts that we use with nbdkit: https://libguestfs.org/nbdkit-cc-plugin.3.html#Using-this-plugin-with-OCaml https://libguestfs.org/nbdkit-cc-plugin.3.html#Using-this-pl...
- mananaysiempre 1y agoCompiler errors won’t cause as many funny consequences with gcc "$0" -o "$@".out && exec ./"$@".out || exit $? # I'd use ${0%.c} not $@ Love this trick too, but the difference, as far as I understand, is that it only works with a Bourne(-compatible) shell, whereas shebangs or binfmt_misc also work with exec().
- AlotOfReading 1y agoYou can also #embed the compiler binary, and execve it to much the same effect as binfmtc. I explored that trick for an IOCC entry that was never submitted because it ended up far too readable.
- ckastner 1y agoOh this is neat. Took me a bit. The shell treats the first line as a comment. It executes the second line, which eventually exec's the binary so the rest of the file do not matter to the shell. And the compiler treats the first line as a preprocessor directive, so it ignores the second line. I initially misread/mistook the first line for a shebang.
- teo_zero 1y agoThe use of $@ doesn't look right to me. In the trivial case exposed here where there are no additional arguments to pass to the .c program, the shell executes gcc "print.c" -o .out && exec ./.out and it works "by chance". In a more complex scenario where print.c expects some parameters, it won't work. For example, ./print.c a b c will result in the shell trying to invoke gcc "print.c" -o "a" "b" "c".out && exec ./"a" "b" "c".out which makes no sense. Are you sure you didn't intend $0 instead of $@ ?
- rwmj 1y agoIt's true, that's a mistake! OTOH we're trying to write self-compiling executable C scripts, so the safety, correctness and good sense ships sailed a while back.
- suprjami 1y agoIs there a way to do this and have the shell remove the temporary file after exec?
- 1vuio0pswjnm7 1y agoThere are many, no doubt #if 0 cc -static -pipe -xc "$0"||exit 100 exec ./a.out #endif int puts(const char *); int unlink(const char *); int main(int argc,char *argv[]){ puts("it works"); unlink(argv[0]); return 0; }
- teo_zero 1y agoYes, but it's not worth it. It's better to forget gcc and use tcc instead, which has the -run flag to compile and run without creating any intermediate file. It's also much quicker than gcc.
- pwdisswordfishz 1y agoOr even /*bin/true ; exec tcc -run "$0" "$@" # */
- nrclark 1y agoI'd have expected this to need a hashbang (#!/bin/sh) at the beginning. Why doesn't it?
- rwmj 1y agoBecause your shell will execute anything that looks like a text file & has +x bit set as a shell script.