Hacker News new | past | comments | ask | show | jobs | submit login
Show HN: Runc – Compile and run C in one command (github.com)
41 points by alcover 8 days ago | hide | past | web | favorite | 43 comments





This looks fun. I can't imagine it being directly useful but the idea itself is fun.

Couple of immediate issues with the repo:

- Sample output in the README should not be prefixed with a "$". That's only for the shell command prompt.

- Use ``` blocks in your README file. It's easier to format multi-line text.

- Don't use $RANDOM, it's not secure. Use mktemp: https://github.com/alcover/runc/blob/73aaecea5a4cd357f7172dd...

- Don't exit with success if the command failed: https://github.com/alcover/runc/blob/73aaecea5a4cd357f7172dd...

- Use Bash strict mode: http://redsymbol.net/articles/unofficial-bash-strict-mode/


re: Bash "strict mode", the shell options are fine but resetting IFS blows the weirdness budget for a default.

You can get saner splitting for that loop over the array by quoting the array expansion:

    for name in "${names[@]}"
Shellcheck lints that, by the way.

Done, done and done. Thank you !

I need a little time to study your 'strict mode' suggestion. I used 'set -e' before but had problems with it.

Would you know how I could detect that input is cat'ed into the script ? ($ cat snippet.c | runc -i). So that I can suppress 'Type your code then CTRL+D'.


> Would you know how I could detect that input is cat'ed into the script ? ($ cat snippet.c | runc -i). So that I can suppress 'Type your code then CTRL+D'.

Stack Overflow suggests http://stackoverflow.com/questions/10022323/ddg#10022396


I think this line should use mktemp as well, to be a tad more safe: https://github.com/alcover/runc/blob/master/runc#L109

This is not a complaint about the name. Just that as a command from the command line, "runc" may clash with the runc container running utility due to potential overlap in the likely users.

Again, it's not the project name just the potential clash at the OS level. Because over the years, I've done it to myself.

https://github.com/opencontainers/runc


Oh. Especially if one puts my script into ~/bin and calls '$ runc ..'

I admit I didn't research the name 'runc'.

Should I rename it ? I like this one because it's short and explicit.


instead of runc, I think ccrun would be a good name. cc is usually the c compiler so ccrun would make sense and be short and explicit.

'ccrun' is nice, thanks. 'crun' would work also.

crun is actually a project that competes with runc. runc (run container) is implemented in go, and crun is a mostly drop-in reimplementation of it in C that is more faster and simpler, it's currently gaining traction in rhel/centos/fedora and suse linux as it was first to implement newer features such as cgroup v2.

Well.. it looks like .com domains : all 4-letters taken ;)

Other ideas: execc, cexec, cmk, mkc, exc, cex (my personal favorite :p).

Compiling and running C code in a single command (without using a Makefile/build system, etc. but by pulling a binary from Homebrew or whatever) feels like a 10x engineering goal, so I therefore put forward: 10cc

As a bonus, it can output "I don't like C code, I love it" in its help/version docs.


You could rename it to "run.c" for "run dot c file." Bash supports many special characters in command names.

"compileAndRunCSource" is explicit.

People could #!bin/bash it however they want.

I only noticed the clash because "runc" seemed familiar.


yes, I would not consider using this given we use the more popular runc

You could alias it ?

What, the standard or OPs?

Why should I have to?


Neat. It wraps GCC.

See also Cling, an interactive C++ interpreter.

https://github.com/root-project/cling


Quick and ugly alternative is chmod+x and add something like this to the top of your file:

  //$(which gcc) $0 -o a.out; ./a.out $@; rm a.out; exit

Clever polyglot file!

Does not work in the spirit of my script though, since you would still need to add headers and main():

  //$(which gcc) $0 -o a.out; ./a.out $@; rm a.out; exit
  int i = 10;
  printf ("%d\n", i);
./snip.c:3:9: error: expected declaration specifiers or ‘...’ before string constant printf ("%d\n", i);

This. My first thought was there is a UNIXy way to do this already.

This is definitely helpful for testing.

Also related is the tiny C compiler and its `tcc -run` command.


I was just about to reply about the same thing:

  #!/usr/bin/tcc -run
  
  #include <stdio.h>
  
  int main() {
    printf("Hello\n");
    return 0;
  }

Or even

  tcc -w -run - <<< 'main() { printf("Hello\n"); return 0; }'           
However, runc seems more convenient to pass in just the statements.

That wasn't quite what I was trying to show with the snippet - I was intimating that you can use tcc to run C directly in something like a shell script.

If you want to make `tcc -w -run` etc. more convenient then:

  alias trun='tcc -w -run - <<<'
  trun 'main() { printf("Hello\n"); return 0; }'
---

I can't edit my parent comment now, but it can be improved with e.g.

  //usr/bin/tcc -run $0; exit
  main() { printf("Hello\n"); return 0; }

> That wasn't quite what I was trying to show with the snippet - I was intimating that you can use tcc to run C directly in something like a shell script.

I know, but the first example in the link was:

  $ runc 'printf("%s\n", "Hello!");'  
  Hello!
So I figured I'd complement your example use with one that was more analogous to that.

> I can't edit my parent comment now, but it can be improved with e.g.

To be honest, I liked your original example more. Using that `//` "shebang" depends on what shell it's invoked from, and it wouldn't work when calling exec from other languages. For example, with your last example using `//`:

  $ python -c 'import subprocess; subprocess.run(["./hello-tcc-double-slash-shebang.c"])'   
  Traceback (most recent call last):
    File "<string>", line 1, in <module>
    File "/usr/lib/python3.8/subprocess.py", line 489, in run
      with Popen(*popenargs, **kwargs) as process:
    File "/usr/lib/python3.8/subprocess.py", line 854, in __init__
      self._execute_child(args, executable, preexec_fn, close_fds,
    File "/usr/lib/python3.8/subprocess.py", line 1702, in _execute_child
      raise child_exception_type(errno_num, err_msg, err_filename)
  OSError: [Errno 8] Exec format error: './hello-tcc-double-slash-shebang.c'
while it would work with the `#!` shebang, since that's handled by the kernel.

why not call it rungcc, like the FSF t-shirt: https://shop.fsf.org/tshirts-hoodies/run-gcc-shirt

D has the `rdmd` command for running D code in one command.

Reminds me of [1] "c" a utility which allows you to execute C code as if it were a script. It's a shame the name is almost unsearchable in Google though...

[1] https://github.com/ryanmjacobs/c


I wrote something similar a few years ago: https://github.com/neilparikh/crepel

I wrote this for a hackathon, so please excuse the messy code :)


This idea has a lot of history behind it. The traditional term is “compile and go”.

https://en.m.wikipedia.org/wiki/Compile_and_go_system


I really like Tom Duff's http://www.iq0.com/duffgram/com.html to compile and run in two commands.

Another take on the same idea: https://git.zx2c4.com/cscript/about/

why not just do

    gcc main.c && ./a.out

That doesn't include the headers. It also leaves a.out on your system.

What are the headers in this context that are not getting included? Shouldn't main.c include any necessary headers?

Yes, but runc includes the headers for you.

I'm sorry, I don't see the benefit of runc including a small list of headers for me. A small test program like main.c ought to be self-contained and might need headers not supplied by runc.

I mean, take it one step further then:

    gcc main.c && ./a.out && rm -f a.out

What is the big deal with just leaving the a.out alone? I might need to run it again, maybe with different arguments. A few a.out files from test programs are not exactly worth fussing over IMHO.

To each their own. If you're in vim, you don't need to leave your editor if you prepend an exclamation mark to the above expression. I often do a lot of prototyping with:

    !gcc main.c -fsanitize=address -Og && ./a.out

Why is this submission submitted a day ago showing up as new again? @dang



Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: