5

I recently started compiling/linking my C files by hand using the gcc command. However it requires all of the source files to be typed at the end of the command. When there are many files to compile/link it can be boring. That's why I had the idea of making a bash alias for the command which would directly type all *.h and *.c files of the folder.

My line in .bashrc is this:

alias compile='ls *.c *.h | gcc -o main'

I found it to work some times but most of the time compile will return this :

gcc: fatal error: no input files

compilation terminated.

I thought that pipe would give the results of ls *.c *.h as arguments to gcc but it doesn't seem to work that way. What am I doing wrong? Is there a better way to achieve the same thing?

Thanks for helping

Community
  • 1
  • 1

3 Answers3

7

A pipe does not create command line arguments. A pipe feeds standard input.

You need xargs to convert standard input to command line arguments.

But you don't need (or want) xargs or ls or standard input here at all.

If you just want to compile every .c file into your executable then just use:

gcc -o main *.c

(You don't generally need .h files on gcc command lines.)

As Kay points out in the comments the pedantically correct and safer version of the above command is (and I don't intend this in a pejorative fashion):

gcc -o main ./*.c

See Filenames and Pathnames in Shell: How to do it Correctly for an extensive discussion of the various issues here.

That being said you can use any of a number of tools to save you from needing to do this and from needing to rebuild everything when only some things change.

Tools like make or its many clones, "front-ends" (e.g. the autotools, cmake) or replacements (tup, scons, cons, and about a million other tools).

Etan Reisner
  • 77,877
  • 8
  • 106
  • 148
  • 2
    NEVER use `*.foo`, use `./*.foo` instead. – Kijewski Nov 09 '15 at 18:58
  • 2
    @Kay While true that's a level of pedantry even I haven't been convinced is generally worth it. It is, unarguably, more correct and safer in the face of all sorts of "bad" file names but in anything not intended for general usage on random input I've never been convinced that the cost is worth the retraining. – Etan Reisner Nov 09 '15 at 19:00
  • 1
    @EtanReisner there will be seldom ever a need to use shell globbing without a relative (or absolute) path. That's why I'd use `./*glob*` in answers, not to teach a bad habit. As an argument for `gcc` it does not really matter I guess, but once $USER wants to implement `clean` in their bash script ... – Kijewski Nov 09 '15 at 19:04
4

Have you tried using a makefile? It sounds like that might be more efficient for what you're trying to do.

If you really want to do it with BASH aliases, you have to use xargs to get standard input to command line arguments.

4

There are several misconceptions here:

  • the pipe redirects the standard output of the first command to the standard input of the second command; however, gcc doesn't accept the files to compile on stdin, but on the command line;
  • the wildcard syntax is not something that is magical just to ls, it's the shell that performs their expansion on the command line;
  • header files are not to be compiled - you compile .c files, which in turn may include headers.

Armed with this knowledge, you'll understand that the correct command something like

gcc -o main *.c

Actually we can do better: first of all, you'll want to change the *.c to ./*.c; this prevents files whose name start with a - from being interpreted as command line options.

Most importantly, you should really enable the compiler warnings, they can be life saver. You'll want to add -Wall and -Wextra.

gcc -Wall -Wextra -o main ./*.c

Finally, it's worth saying that by default you are compiling with optimizations disabled. If you are debugging that's OK, but you want also to add -g to have an executable usable in debugging; otherwise, if the target is speed you should at least add -O2.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
  • 1
    The standard way to prevent files with names starting with `-` from being seen as input files is to add a `--` operand right after the last option. – fuz Nov 09 '15 at 19:43
  • 1
    @FUZxxl: that's supported by many commands (including gcc) but it's not universal. Also, it's not possible to use it for arguments other than the last one. – Matteo Italia Nov 09 '15 at 20:02
  • `--` is part of POSIX and all applications that use `getopt()` for parsing or that follow the [UCB utility conventions](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html) should obey it. What do you mean with “arguments other than the last one?” A command's arguments are always first options and then operands except with GNU utilities, these don't follow the standard for god knows what stupid reason. Notice further that `-llibrary` is an operand, not an option to `cc`. – fuz Nov 09 '15 at 20:07
  • 1
    @FUZxxl, there are actually people and programs who don't follow conventions, hard to believe but it's true. ;) Actually I just used [qpdf](http://qpdf.sourceforge.net/) which does not understand `--`. – Kijewski Nov 09 '15 at 20:25
  • 1
    @FUZxxl: what Kay said. Life is too short to learn about UCB and who does abide to it, who says to do so but actually fails to comply in some cases and to take a definite position in the multifaceted debate about the pros and cons of each and every standard of command line options and its nuances of purity. Honestly, I don't give a damn; I just want to avoid bizarre stuff in case someone puts a `-rf` file where my scripts are going to operate, and I prefer to learn once the safer globbing syntax rather than remembering all the exceptions for the various commands. – Matteo Italia Nov 09 '15 at 21:01