We are required to compile C source codes using gcc in this manner:
gcc -ansi -pedantic -Wall program.c
I'm wondering how can I 'automate' this so when I enter:
gcc program.c
It will automatically compile with the 3 switches. Is this possible?
You can also use the implicit rules of make, so that you don't have to write a makefile for every program. Make will automatically call the compiler if you say make foo and there exists a foo.c file in the current directory. To add flags to this define the variable CFLAGS in your environment, e.g. in bash add export CFLAGS="-Wall -pedantic -ansi" to .bashrc.
If your program depends on multiple files however you'll have to create a makefile, but for C compilation you can get away with just listing dependancies so long as one of them has the same base name as a target.
For example for this makefile:
# Makefile
foo:foo.o bar.o
running make will execute the commands
gcc $CFLAGS -c -o foo.o foo.c
gcc $CFLAGS -c -o bar.o bar.c
gcc -o foo foo.o bar.o
without you having to add any rules.
To automate the build of any number of build steps / complex parameters, you should use a makefile.
Once you have a makefile you simply need to type: make
alias gcc="gcc -ansi -pedantic -Wall"
But as #Brian said, you really should use a makefile, or better, a build system like CMake or SCons.
A makefile would be the traditional way, especially as part of a larger build process.
If you frequently want to build without a makefile, you could define an alias in your .bashrc or equivalent: alias gcc=gcc -ansi -pedantic -Wall.
You can use a shell script that takes some cues by how its called and invokes make after setting CFLAGS appropriately for the occasional one-off build.
Lets say you have /usr/bin/compile , which is a shell script that looks at $0 to see what name actually invoked it. You then make symbolic links to it named pedantic, fullwarn, etc.
In the shell script itself, something like:
OLDCFLAGS=$CFLAGS
WHATAMI=$(basename $0)
case "$WHATAMI" in
pedantic)
export CFLAGS="-Wall -pedantic -ansi"
make $#
exit $?
;;
c99)
export CFLAGS="-std=c99 ... ... ..."
....
Then, to compile foo.c with the extra naggy flags:
pedantic foo
This is handy, as I said for one-off builds, e.g trying to compile code that someone posted in a question, or working out how to use a new library, etc.
For anything else, just use a makefile, as others have said.
Related
I have reinstalled mingw in my system and downloaded the gcc compiler.
I was shocked after compiling the first file which was "subject.c" but the name of the compiled file which gcc returned was "a.exe". It should be "subject.exe" but do not know why this happened.
Can anyone please explain the reason behind this ?
expected:
gcc subject.c
ls
subject.c subject.exe
tried:
gcc subject.c
ls
subject.c a.exe
-o can be used to give the name of the output file.
For example,
gcc -Wall -Wextra -pedantic subject.c -o subject.exe
(Do enable your compiler's warnings!)
gcc names its output files, in the absence of other instructions, a.out or a.exe depending on system environment because that is what it's supposed to do.
To override this default behavior, you can use the -o flag which tells gcc that the next argument is the desired name for the output file. For instance:
gcc -o subject.exe subject.c
There is no automatic functionality built into gcc to strip a source file of its file extension and add .exe to the end but this can be done manually with Makefiles or other similar scripts, for instance you can write a Makefile with the following contents:
%.exe: %.c
gcc -o $# $<
Then a command like make subject.exe would be translated to gcc -o subject.exe subject.c, which may be what you're looking for.
There is functionality built into gcc to strip source files of their extensions during different parts of the compilation process, which may have been what confused you. For instance a call like gcc -c subject.c can be expected to produce an object file called subject.o, likewise gcc -S subject.c can be expected to produce an assembly language file called subject.s, however this does not apply to executable files not only for historical reasons, but because programs can be compiled from multiple source files and there is not always a clear way to choose a name for the executable output.
In my makefile for a C project, I have set the CFLAGS variable as follows -
CFLAGS=-ansi -pedantic -Wall -Wextra -O2 -isystem $(SQLITEDIR)
I expected this variable to be used in the rule for building object files since the flags affect the compilation step
However, in the GNU make manual
https://www.gnu.org/software/make/manual/make.html#Using-Implicit
I see the following example -
foo : foo.o bar.o
cc -o foo foo.o bar.o $(CFLAGS) $(LDFLAGS)
I think this is a rule for the linking step so I understand it why it include LDFLAGS, but what is the purpose CFLAGS here?
(I am guessing that you are using GNU make on some Linux system)
You are right in your use of CFLAGS (but I would add -g there). But I am not sure you need -isystem $(SQLITEDIR), it probably can be -I $(SQLITEDIR) instead. The -isystem directory option to GCC is rarely useful.
Read first the documentation about Invoking GCC, assuming you are using the GCC compiler. BTW, you could have CC= gcc in your Makefile. If your compiler is not GCC but something else (e.g. Clang/LLVM) read its documentation.
Then, run make -p to understand the builtin rules of your GNU make (there are many of them). You'll find out that many builtin rules are using CFLAGS etc. And that is why it is simpler to have a CFLAGS variable in your Makefile; if possible, take advantage of some builtin rules known to make.
BTW, you could avoid using any builtin rules and variables, but that is poor taste.
The POSIX standard defines some options understood by cc and by make (and some minimal rules for make). Both GCC and GNU make have much more. Read documentation of GNU make.
CFLAGS usually contain some (optimization or other) flags (e.g. -O or -g, or -pthread) which are also relevant at the linking step (assuming you link with gcc, which will invoke ld). That is why you usually link using gcc (as $(CC) in your recipe) with both LDFLAGS and CFLAGS.
You could use make --trace or even remake (as remake -x) to debug your Makefile.
I'm very new to C programming and I want to know what to write in a Makefile to compile a single .c file.
Say I have a multiple .c files in one folder )namely sample1.c, sample2.c, sample3.c, etc) and I only want to compile a specific filename.
I want to only type "make sample2" which will compile and have an output called sample2 (pretty much the .c name will be maintained).
I've read several solutions and someone might have suggested this but didn't work.
SRC = $(shell find . -type f -name \*.c)
executable: $(SRC:.c=.o)
gcc -std=gnu99 $# $^
What do I need to do to make it work?
Converting a comment into an answer.
You don't need a makefile for that: make sample2 will compile sample2.c to create the program sample2.
You could use /dev/null as the name of the makefile if you want (or if you need to ignore an existing makefile):
make -f /dev/null sample2
That compiles with the default options, of course. If you want to use more stringent flags, then you might do this (assuming that the existing makefile is expendable):
echo 'CFLAGS = -Wall -Wextra -Werror -std=c11 -O3 -g' > makefile
make sample2
or some variant on that theme, such as:
make -f /dev/null CFLAGS="-Wall -Wextra -Werror -std=c11 -O3 -g" sample2
In short, make knows how to compile single C files into the executable of the corresponding name (minus the .c suffix) without needing any explicit makefile. You can tweak how it compiles that file if need be.
okay so I'm on OS and I use terminal to compile my c code. Whenever I make a file using nano or vim called "tst.c" (or whatever the name might be ) then I compile using (my teacher told me to use this everytime so I don't think this is the problem:
gcc -Wall -std=c99 -o tst.c ./tst.c
then it turns into binary I'm guessing. But when I try to edit it again, it has all these weird encryptions I'm guessing like:
��������H���__PAGEZERO��������������������������������������������������������ÿ��__TEXT����������������������������������������������������__text����������__TEXT����������`�����*�������`���������������Ä������������__stubs���������__TEXT����������ä������������ä��������������Ä�����������__stub_helper���__TEXT����������ê������������ê���������������Ä������������__cstring�������
So, question is, how do I revert so I can edit and not make a new file every time???????
You're overwriting your original source file with the compiled executable because of the -o option:
gcc -Wall -std=c99 -o tst.c ./tst.c
^^^^^^^^
You'll need to specify a different output file name in the -o option:
gcc -Wall -std=c99 -o tst tst.c
Otherwise, you can leave the -o option off entirely, and the compiled executable will be written to a file named a.out.
Eventually, you'll want to automate all of this with the make utility, but for now just be aware of how the -o option works.
the -o (name) flag means you are storing the output into whatever you used for name.. so if you add .c to the end of the name you'll see lots of interesting stuff. Man pages are pretty awesome when learning about what each flags do.
Is there a way of telling gcc to use the c99 standard when compiling c files as a default?
I want to avoid giving it the -std=c99 parameter all the time.
I assume I can do this by creating an alias in the .bashrc file, but seems to be rather inelegant.
You may call c99 instead of gcc (wrapper for gcc, if it's available on your system) or try to modify your gcc spec file. More information here: http://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Spec-Files.html
Here's an unexpected answer. Use a Makefile!
Pros:
Simply type make to build
All options are automatically handled in the build process.
While you're at it, go ahead and enable all warnings, as is good to do. See this.
Easy to scale up to multiple source files
Can handle multi-step builds involving different tools
Cons:
Another tool to learn, another thing to get wrong.
Consider this source:
#include <stdio.h>
int main() {
printf("Hello!\n");
int x = 4;
printf("%d\n", x);
return 0;
}
You could make a Makefile like this:
(Disclaimer, I don't actually know how to write them)
CC=gcc
CFLAGS=-Wall -pedantic -std=c99
LDFLAGS=
SOURCES=$(wildcard *.c)
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
.PHONY: clean
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
clean:
rm -f *.o $(EXECUTABLE)
And it builds for me.
Likewise, if you remove the -std=c99, it shouldn't be valid C89 code, and indeed, typing make brings up the build error.
Custom compilation suggests you have at a working knowledge of compilers, standards, and basic flags / options. For that reason, I suggest you set shell variables in your .bashrc, .tcshrc, etc., and use them on the command line.
Since the choice of dialect can have an effect on linking: CC="gcc -std=c99", lets you invoke separate compilation commands using $CC -c -O2 ... foo.c, and is also picked up as the default for configure scripts, etc. Of course, you can always override a configure script with CC="gcc -std=c90" or CC="clang". The same applies to a preferred CFLAGS value, e.g.,
CFLAGS="-pipe -W -Wall -O2 -march=core2"
Allows for $CC $CFLAGS -c foo.c commands, and both environment variables are used by default with configure scripts, unless you explicitly override them. I think this is more useful than aliases. But perhaps I've just grown used to my own setup:)
Both of the proposed solutions are, in my opinion, almost what you want, but neither quite gets there.
Makefile solution
As seen here, by defining variables in your Makefile but not defining targets, you can use the make command like a customized pass-through to GCC. So if you create a Makefile in your "sandbox" directory (or wherever you're compiling outside of a real build system) and define the C*FLAGS vars, you'll essentially get what you want. An example Makefile:
CFLAGS=-Wall -std=c99
CXXFLAGS=-Wall -std=c++14
Now, make foo will turn foo.c into an executable called foo.
If you want to do this trick in multiple directories, put your makefile in a known location--say, ~/sandbox--and create the following alias (or something like it) in your .bashrc:
alias usestdmake="ln -s ~/sandbox/Makefile"
Then you can quickly compile a single file anywhere on your machine:
usestdmake
make foo
This has the added advantage of giving the output executable an appropriate name (foo in this case). It has the disadvantage of disabling tab-completion for your compile command (make fo<tab> does nothing, at least on my system).
Pure bashrc solution
The CC/CFLAGS variables mentioned in Brett Hale's answer are fairly standard, so it might be a good idea to define them in your bashrc. You can then use these variables inside of aliases.
In your .bashrc:
CFLAGS="-Wall -std=c99"
CC=gcc
# Use single-ticks to ensure that the variables are evaluated when the alias is evaluated.
alias mycc='$CC $CFLAGS'
On the command line:
cc foo.c # Compile with default CFLAGS
CFLAGS="$CFLAGS -O2" cc foo.c # Compile with modified CFLAGS