views:

737

answers:

5

So this is probably a long shot, but is there any way to run a C or C++ file as a script? I tried:

#!/usr/bin/gcc main.c -o main; ./main

int main(){ return 0; }

But it says:

./main.c:1:2: error: invalid preprocessing directive #!
+6  A: 

CINT:

CINT is an interpreter for C and C++ code. It is useful e.g. for situations where rapid development is more important than execution time. Using an interpreter the compile and link cycle is dramatically reduced facilitating rapid development. CINT makes C/C++ programming enjoyable even for part-time programmers.

Eli Bendersky
Interesting. I'm hoping for something that would have the same result as gcc $stuff; ./filename though. This is already more than I was expecting though.
Brendan Long
Brendan - If you want to do that you are going to have to write a script in bash or such to compile and call the program.
Mimisbrunnr
@Brendan: why do you need this, really? To me it doesn't make much sense using C and C++ this way
Eli Bendersky
No real need, I was just wondering. It would be a funny way to distribute a program.
Brendan Long
+15  A: 

For C, you may have a look at tcc, the Tiny C Compiler. Running C code as a script is one of its possible uses.

Remo.D
Oh I like this one. All you have to do is add `#!/usr/bin/tcc -run`
Brendan Long
@Brendan: I'm also quite fond of tcc, especially with regards to compile times; you'll have to beware of compiler-bugs, though
Christoph
+8  A: 
$ cat /usr/local/bin/runc
#!/bin/bash
sed -n '2,$p' "$@" | gcc -o /tmp/a.out -x c++ - && /tmp/a.out
rm -f /tmp/a.out

$ cat main.c
#!/bin/bash /usr/local/bin/runc

#include <stdio.h>

int main() {
    printf("hello world!\n");
    return 0;
}

$ ./main.c
hello world!

The sed command takes the .c file and strips off the hash-bang line. 2,$p means print lines 2 to end of file; "$@" expands to the command-line arguments to the runc script, i.e. "main.c".

sed's output is piped to gcc. Passing - to gcc tells it to read from stdin, and when you do that you also have to specify the source language with -x since it has no file name to guess from.

John Kugelman
I get lots of ld errors with this one :\
Brendan Long
@John Kugelman: Can you please add an explanation for what you are doing in `runc`? Specifically, what do you achieve using `sed`?
Lazer
@eSKay - Sure thing.
John Kugelman
@John Kugelman: What is th need for putting `#!/bin/bash /usr/local/bin/runc` as the first line in `main.c` when you are going to strip it using `sed` anyways?
Lazer
@eSKay - That line tells the system what program to use to "run" the script. Without it bash will try to interpret the `.c` file as a bash script and bomb out with a syntax error.
John Kugelman
@John Kugelman: thanks! I get the complete idea now. very clever!
Lazer
You should use mktemp instead of a.out otherwise you get problems when running two different C-scripts at the same time...Also, the C-script doesn't compile as a real C program because of the hashbang at the top, though I'm not sure what you can do about that...
Graham
@Graham well that's why he strips out the #! with `sed` before compiling.
Pointy
+5  A: 

Since the shebang line will be passed to the compiler, and # indicates a preprocessor directive, it will choke on a #!.

What you can do is embed the makefile in the .c file (as discussed in this xkcd thread)

#if 0
make $@ -f - <<EOF
all: foo
foo.o:
   cc -c -o foo.o -DFOO_C $0
bar.o:
   cc -c -o bar.o -DBAR_C $0
foo: foo.o bar.o
   cc -o foo foo.o bar.o
EOF
exit;
#endif

#ifdef FOO_C

#include <stdlib.h>
extern void bar();
int main(int argc, char* argv[]) {
    bar();
    return EXIT_SUCCESS;
}

#endif

#ifdef BAR_C
void bar() {
   puts("bar!");
}
#endif

The #if 0 #endif pair surrounding the makefile ensure the preprocessor ignores that section of text, and the EOF marker marks where the make command should stop parsing input.

Ephphatha
Not what I was looking for, but close, and definitely entertaining.
Brendan Long
+2  A: 

Variatn of John Kugelman can be written in this way:

#!/bin/bash
t=`mktemp`
sed '1,/^\/\/code/d' "$0" | g++ -o "$t" -x c++ - && "$t" "$@"
r=$?
rm -f "$t"
exit $r


//code
#include <stdio.h>

int main() {
    printf("Hi\n");
    return 0;
}
ony