pipeline echo to gcc?

2020-07-15 06:45发布

To call printf("Hello!"); in C from terminal I use

echo '#include<stdio.h>
void main()
{
printf("Hello!");
}' > foo.c

and then call gcc foo.c to make the output. Unfortunately, the pipelining

echo '#include<stdio.h>
void main()
{
printf("Hello!");
}' | gcc 

fails complaining for no input file. Ultimately, I want to have a script where I can compile a C command from terminal with ./script [command]. Any suggestion would be appreciated.

4条回答
一夜七次
2楼-- · 2020-07-15 07:20

Yes, but you have to specify the language using the -x option. Specify input file as stdin, language as C using -xc (if you want it to be C++, use -xc++). So in your case the command would be

echo '#include<stdio.h>
void main()
{
printf("Hello!");
}' | gcc -o output.o -xc -

You can read more about Command Line Compiler Arguments: see Invoking GCC chapter.


However, as @Basile says, it is not worth the effort to avoid dealing with C files. Check his answer for more information.

查看更多
Juvenile、少年°
3楼-- · 2020-07-15 07:22

Instead of pipeing it, why not have the script run the command:

gcc foo.c

whilst still keeping the redirection into foo.c

echo '#include<stdio.h> 
void main()
{
printf("Hello!");
}' > foo.c
gcc foo.c

You can then delete foo.c if you would like after gcc creates the executable by adding at the end

rm foo.c
查看更多
beautiful°
4楼-- · 2020-07-15 07:26

Other answers are explaining how to make gcc read C code from stdin, but notice that in practice
it is not worth the effort to avoid dealing with C files.

(I am guessing you are using some POSIX operating system like Linux; if not, adapt my answer to your OS and compiler)

Emitting C code automatically is usual practice (and many academic programming languages are compiling to C, and many builds are using generated C code, e.g. from bison). But there is no much gain to use pipes and stdin, because a C compiler takes a lot of time (notably for optimization, which you often want, e.g. by compiling with gcc -O2).

So my recommendation is to put the generated C code in a genuine file (perhaps some temporary one which should be removed later appropriately). That file could be on some tmpfs file system if disk performance is an issue (and in practice it never is for gcc compiled source code), and that file could be temporary (e.g. removed later) if you want it to.

Notice that the gcc program is generally using temporary files internally itself (e.g. for generated assembler files or object files). You'll see them if you add -v to your gcc compilation command, e.g. if you compile foo.c with gcc -v foo.c -o fooprog. So there is no practical reason to avoid a C source file (since gcc uses temporary files anyway!).

If you want to generate code on the fly in a running program, you could generate temporary C code then compile it as a temporary plugin (with position-independent code) then dynamically load that plugin (e.g. using dlopen(3) & dlsym(3) on Linux); but you could also use JIT compiling libraries like GCCJIT or LLVM or asmjit, etc.... Of course this requires some support from your operating system (e.g. to grow your virtual address space): in pure standard C11 (read n1570), the set of functions is fixed at build time since defined in the union of your translation units (the set of .c files comprising your program), and you cannot generate code at runtime.

If you want to generate some C program in some shell script, better use temporary files, e.g. with tempfile, mktemp etc... (and use trap builtin on EXIT and on TERM signal to remove the temporary files when the script terminates).

If you generate some temporary C code in your build, good build automation programs (e.g. GNU make or ninja) can be configured to remove these temporary C files (e.g. read about intermediate files for make).

Look also into homoiconic programming languages like Common Lisp. For example SBCL is compiling into machine code at every REPL interaction.

查看更多
欢心
5楼-- · 2020-07-15 07:31

I have done this in the past by doing

ln -s /dev/stdin stdin.c

Now stdin.c is a symlink to /dev/stdin, i.e. a magic file "containing" anything I type or pipe to it. But the filename ends in .c, so any C compiler should treat it as a C file. Things like

(echo '#include <stdio.h>'
 echo 'int main(void) { printf("Hello, world!\n"); }') |
    cc stdin.c

work just fine.

(Obviously this assumes you're using a Unix-like system with symbolic links and /dev/stdin.)

查看更多
登录 后发表回答