how to write a makefile in linux for a c program - c

i have written a c program for doubly-linked-list in linux. the program is named as program2.c.
i have compiled it using "cc program2.c -o out2".
it compiled and also executed fine.
even also tried writing a makefile.my makefiel includes
all:doublelinkedlist
doublelinkedlist:program2.c
gcc -Wall -Werror -O2 -o $# $<
clean :
\rm -fr doublelinkedlist
when i did make it gives me the errors.
can any one please help me writing a makefile.

When using a makefile, you also started using the -Wall -Werror flags. This is a very good thing.
Now the compiler looks for more suspicious things in your program, and refuses to compile if it finds anything. This can be a great help in catching bugs.
However, these warnings mean your program doesn't compile, and you'll need to fix them, by changing the code so that the compiler will be sure all is OK (as far as the compiler can check - of course the code can still contain bugs).
Common issues are mixing different types and not paying attention to the const keyword. But for help with specific warnings, you'll need to show the warnings and the code. Or better - search for each of them in StackOverflow, and I'm sure you'll find good answers.

Related

How exactly "make all" works?

So I am studying makefiles usage. Let's say I 've many functions fun_i.c where i is in [1,100]. I have wrote them all in seperate .c files in order to make faster compilation when I only change some of them. I need to create a Makefile. I was thinking something like that:
all : program
program: fun1.o fun2.o ........ fun100.o main.o
gcc -o program fun1.o fun2.o ..... fun100.o
fun1.o: fun1.c
gcc -c fun1.c
.
.
.
fun100.o: fun100.c
gcc -c fun100.c
main.o : main.c
gcc -c main.c
I 've read many articles online talking about how the target "all" makes sure that everytime I change something in a function and I call make it will update only what changes (so I'm going to avoid uneccessary recompilation).
However, I am not sure if I am using it right here. I checked my makefile ( with 2 functions though) and it worked fine. But I am not sure if that's the way to take advantage of all here.
I tried to remove it and just leave program and below.. there and it worked as fine.
What am I missing?
Could you may provide examples that all is critical?
I 've read many articles online talking about how the target "all" makes sure that everytime I change something in a function and I call make it will update only what changes
all does not mean anything. It's just a convention. You have to define the targets correctly to do what you want. If you want make all to recompile everything, you need to define it so that it does that.
so I'm going to avoid uneccessary recompilation
In practice, I'd say that this is a completely unnecessary concern, and it's a waste of time creating makefiles that does this. If you have a large project you should not create makefiles manually. You use a build system like cmake.
If the project is small and only contain a few files, then the compilation time is in general not an issue. For a small project, my goal with a makefile would be to not have to type the compiler flags all the time.
Here is a makefile that would work fine for most very small projects like school assignments:
CFLAGS=-Wall -Wextra -pedantic -std=c17 -fsanitize=address
LIBS=-lm -lpthread
program:
gcc $(CFLAGS) $(LIBS) *.c
clean:
rm -rf *.o *~
Your makefile is fine, both with and without all: program.
The word all has no special significance in makefiles, using is just a convention. In your makefile all has no recipe (i.e. no commands associated with it), so make all and make program are equivalent.
Note that if you don't specify a target when invoking Make (e.g. make as opposed to make program), the first target in the makefile is built.

Best practices regarding warning outputs when compiling in gcc? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I'm learning c and am compiling all my programs using gcc in linux subsystem for windows.
I learned that I can include some flags by the gcc standards. Some include the basic -o or -lm.
I discovered the -Wall flag and it has outputted some warnings in my shell that I fix.
Right now my usual gcc compilation line usually lies along the lines of cc -Wall -lm -o file.exe file.c.
I recently learned that there are a lot of other flags that can be included, some regarding warnings; one is -w, which is supposed to show even more warnings than -Wall, so my question is -
1- Should I always specify -w? or is there any drawbacks or maybe even incorrect issued warnings?
2- Also, what are the best practices when compiling a program, i.e., what options/flags do you always turn on?
The more professional you become the more warnings you strive to enable. My current favorite set is -Wall -Wextra -pedantic which gives a good average.
If you think you receive a false warning, think again. Almost always the compiler is right. Until you become an intimate expert with the C standard you better ask, for example here on SO.
Some think that -Werror has some value, and for their development process they are probably right. Since I use some kind of build control software (namely "make") I don't need it, because GCC returns non-zero values on warnings, too.
All other flags depend on the purpose of the command. Some examples:
-o is great to define the name of the output file.
(EDIT)-O… sets the optimization level; some years ago -O3 might have some problems but today it should be fine.
-s strips the debug information from the output; good for the release version.
-g includes debug information to the output; there are variants depending on your goal.
-Wl,--wrap… is really sophisticated for special debugging and/or testing; read its documentation.
Another best practise can be considered the often use of -Wfatal-errors
GCC compiler errors can sometimes be several pages long (especially so if you ever have to compile C++ code). There are several reasons for while compiler errors can be so long; a typical example is some missing brackets at the top of the file, which causes the compiler to report errors for many lines of the remainder of the file.
Seasoned developers know to initially direct their attention on the top-most error, and fixing that often solves all the following pages of errors. To help with this working practise, you can add the -Wfatal-errors to tell gcc that you only want to see the first error, and that it should stop trying to compile the rest of the code once a compilation error is detected. Thus you never get the daunting pages of output that you have to scroll through.
Best practice is then switching to and from this -Wfatal-errors mode, or just leave it mostly on, only occasionally turning it off when you would like to see more errors for a particular problem.
Should I always specify -w?
-w removes all warning messages. You should not use -w.
If you meant -W, it's an old flag for -Wextra, has the same meaning as -Wextra.
Also, rules are not absolute. Not always, there are project specific needs and recommendations. If I write a short program, I sometimes use like gcc -ansi -xc - <<<'a;b;main() { printf("%d\n", a * b); } because I'm in a hurry. But usually, if not always, you should enable as many warnings as you can.
or is there any drawbacks or maybe even incorrect issued warnings?
The drawbacks of too many warnings are coming from too many enabled warnings - clutter in compiler output, while irrelevant warnings hide important stuff. The warnings I do not like:
unused functions -Wunused-function
unused function parameters -Wunused-parameter
Although code may be perfectly fine, ton of "unused function" warnings may be issued, while these functions may be used in like different project configuration chosen by different macro definitions.
what are the best practices when compiling a program, i.e., what options/flags do you always turn on?
I recommend for warnings: -Wall -Wextra -Wwrite-strings -Wno-unused-function -Wno-unused-parameter
I also recommend following flags to write safe code and protect against runtime mistakes: -D_FORTIFY_SOURCE=2 -fsanitize=address -fsanitize=undefined -fsanitize=leak -fsanitize=pointer-subtract -fsanitize=pointer-compare -fno-omit-frame-pointer -fstack-protector-all -fstack-clash-protection -fcf-protection
Fun fact: -Wwrite-strings is not enabled with -Wall -Wextra and looks like a valuable warning to me.
See also redhat recommended compiler and linker flags for GCC.
With gcc10 static analyzer options are also worth a look.

Makefile issues - fatal error in reader

I am having some issues with a makefile I am creating for a school project. I am compiling and assembling a C file and a SPARC assembly file (respectively) and linking them. I'm working in a Unix environment. Here is the makefile:
proj09.exe: proj09.driver.o proj09.support.o
<tab>gcc -Wall proj09.driver.o proj09.support.o -o proj09.exe
proj09.driver.o: proj09.driver.c /user/cse320/Projects/project09.support.h
<tab>gcc -Wall -c proj09.driver.c /user/cse320/Projects/project09.support.h
proj09.support.o: proj09.support.s
<tab>gcc -Wall proj09.support.s
When I try to make it, though, I get a reader error, specifically:
"Fatal error in reader: proj09.makefile, line 2: Unexpected end of line seen"
Now I know that usually this means that something is formatted incorrectly, but I have no idea what it could be in this case. Also, I am not 100% sure that this is the correct code for the makefile (specifically the assembling of my support.s file, and the linking of both files). I apologize if this is a repeat question, I looked through the archives beforehand and couldn't find anything of use. Any help would be greatly appreciated!
EDIT: I don't see why this would make a difference, but I am using gedit to actually write the code and then transferring the files into SSH for linking.
As Joachim told you, the lines should be indented by tab, not by spaces, so the second line should look like:
[TAB]gcc -Wall proj09.driver.o proj09.support.o -o proj09.exe[NEWLINE]
where [TAB] means TAB character.
Also there shouldn't be any spaces after the command. That's why I've put [NEWLINE] char.
Aside from the spaces and tabs, this doesn't generate an object file, shouldn't even compile (unless it has main()):
gcc -Wall proj09.support.s
You should use -c here too:
gcc -Wall -c proj09.support.s
Note: if you're working on Unix/Linux lose the .exe

Alias CC to Refer to Clang in a Shell?

Any caveats or gotchas to aliasing cc to refer to Clang within my default shell - zsh (presumably by editing my .zshrc file) while leaving cc aliased to gcc in another shell (bash)?
I find Clang much easier to use mainly because it's warnings and error messages are much more readable and understandable than those of gcc. I will be enrolled in a Unix programming course next semester (purely in C) and am expected to have cleared any gcc -Wall warnings before submission of an assignment.
What I am trying to do is do most of my developing using Clang within my default shell (zsh) using a makefile that refers to the compiler as just cc. Once satisfied I would run it once, as a test, via bash (invoking gcc as the compiler) before submitting. The submitted makefile with cc as the compiler would then invoke gcc for the instructor, making it transparent to them. I am supposed to submit makefiles with each assignment.
I know this just seems like lazyness since I can re-edit the makefile each time, but I am trying to leave less room for error.
Just run
make CC=clang
or
make CC=gcc
or perhaps
make CC='gcc -flto -Wall'
(reminder: -flto should be passed at compile and at link time).
I won't comment on whether this is fine or not, but there is an easier way. Just use a variable in your Makefile to whatever you want the default to be:
CC=gcc
Then you can override this when you invoke make:
make CC=clang

C gcc compilation question and makefiles

Not even quite sure what my question is. The short of it is, for a class I'm supposed to add some functionality to this c file, and it came with a handy makefile.
CFLAGS=-DUNIX -lreadline -lcurses -ansi -pedantic-errors
DEBUG=-g
#DEBUG=
all: shell
shell: shell.c parse.c parse.h
gcc $(CFLAGS) $(DEBUG) shell.c parse.c -o shell
clean:
rm -f shell *~
I have to add features to shell.c. I'm very new to C (usually use c++ or c#) so I'm testing out little things in a separate little tests.c file. Things like, see what exactly certain system calls return, how to printf them right, etc. Anyway, tests.c seems to be conforming to different c compiler standards or I'm compiling it wrong. If I accidentally use // to comment something out or declare a variable somewhere other than at the start in shell.c, the compiler yells at me. It doesn't care in tests.c.
I compile tests.c with "gcc tests.c -o tests"
If I compile the shell using "gcc shell.c parse.c -o shell" it compiles fine, but running it simply gives me a segmentation fault. I would love to ask my TA about this, but every time I as him something he answers a completely different question...
Any thoughts on what's going on here? Perhaps a point in the right direction at least?
The problem is that your makefile includes -ansi -pedantic-errors flags for the compiler. This forces it to use a very old version of C. Perhaps this Makefile was provided by your instructor and he wants like that? It is not uncommon.
To use these new features (// comments, automatic variables anywhere in a block) just drop these two flags. If you have the freedom, I recommend also using -std=c99 -Wall.
To get GCC to accept C99 conventions, tell it to do so:
gcc -std=c99 ...
gcc -std=gnu99 ...
So, add -std=gnu99 to your CFLAGS value, and remove -ansi which is equivalent to -std=c89. If you must code to C89 standards, do not use // comments.
We can't tell what causes the core dump - but it could be that you're trying to modify a string literal somewhere, or any of a large number of other problems.
The -ansi -pedantic-errors prevents the impurities like // and variable definitions in the middle of the function. Remove that and you should be able to sin away.
As for the segmentation fault, your best bet is to run your program through gdb to see where it crashes.
Why are you compiling by calling gcc directly instead of using the makefile? The makefile adds a number of additional command-line gcc options which are most likely important. Do you see the same behavior if you compile using make all?
Since you are new to C, I would recommend adding -Wall to the CFLAGS line. This will enable all compiler warnings, which may alert you to a subtle error that you might have otherwise missed.

Resources