How to use Makefile from a very simple example [closed] - c

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 3 years ago.
Improve this question
I'm trying to learn how Makefile works, so I decided to try it with a very simple code. This is what I wrote:
/* justify.c */
#include <stdio.h>
#include "line.h"
#include "word.h"
int main(void) {
printf("I'm in the main.\n");
read_word();
write_line();
}
/* line.h */
void write_line(void);
/* line.c */
#include <stdio.h>
#include "line.h"
void write_line(void) {
printf("write_line\n");
}
/* word.h */
void read_word(void);
/* word.c */
#include <stdio.h>
#include "word.h"
void read_word(void) {
printf("read_word\n");
}
now ... if I do everything from the terminal it works:
> gcc -c justify.c
> gcc -c line.c
> gcc -c word.c
> gcc -o justify justify.c line.c word.c
but if I try to do everything with a Makefile it gives me an error:
# Makefile
justify: justify.o line.o word.o
gcc -o justify.o line.o word.o
justify.o: justify.c line.h word.h
gcc -c justify.c
line.o: line.c line.h
gcc -c line.c
word.o: word.c word.h
gcc -c word.c
> make justify
Undefined symbols for architecture x86_64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

No pun intended, but you are making make a bit harder than it needs to be. In your case with the source and headers all in the same directory, it is quite simple to use wildcards to allow make to handle the rest. For example with three simple variable declartions in your Makefile, you can tell make what your sources are, your includes and how to generate an object file for each of the source files that isn't the application name.
For starters, specify your application name:
# application name
APPNAME := justify
If needed, set your compiler variables, e.g.
# compiler
CC := gcc
CCLD := $(CC)
Now make knows your application name is held in APPNAME which you access like any other variable in a Makefile as $(APPNAME).
Now just use wildcard to collect all sources and includes in variables as well, and let make associate the object file output:
# source/include/object variables
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:%.c=%.o)
Set your compiler/linker/library flags:
# compiler and linker flags
CFLAGS := -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast
LDFLAGS :=
# libraries
LIBS :=
Now create your default target for make (note: there must be a tab-character '\t' in front of each rule):
all: $(OBJECTS)
$(CCLD) -o $(APPNAME) $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(LIBS)
A rule to compile all sources to objects:
$(OBJECTS): %.o : %.c
$(CC) $(CFLAGS) -c -o $# $<
(see: What do the makefile symbols $# and $< mean? for explanation of the automatic variables used)
And finally a target for clean:
clean:
rm -rf $(APPNAME) *.o
A complete example for your files would be:
# application name
APPNAME := justify
# compiler
CC := gcc
CCLD := $(CC)
# compiler and linker flags
CFLAGS := -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast
LDFLAGS :=
# libraries
LIBS :=
# source/include/object variables
SOURCES := $(wildcard *.c)
INCLUDES := $(wildcard *.h)
OBJECTS := $(SOURCES:%.c=%.o)
# target for all
all: $(OBJECTS)
$(CCLD) -o $(APPNAME) $(OBJECTS) $(CFLAGS) $(LDFLAGS) $(LIBS)
# strip only if -DDEBUG not set
ifneq ($(debug),-DDEBUG)
strip -s $(APPNAME)
endif
$(OBJECTS): %.o : %.c
$(CC) $(CFLAGS) -c -o $# $<
clean:
rm -rf $(APPNAME) *.o
(note: a rule to strip the executable was also added to the all: target)
Example Build
With your Makefile source and include files in a common directory, e.g.
$ ll
total 24
-rw-r--r-- 1 david david 668 Nov 6 12:38 Makefile
-rw-r--r-- 1 david david 161 Nov 6 12:31 justify.c
-rw-r--r-- 1 david david 106 Nov 6 12:32 line.c
-rw-r--r-- 1 david david 37 Nov 6 12:31 line.h
-rw-r--r-- 1 david david 104 Nov 6 12:32 word.c
-rw-r--r-- 1 david david 36 Nov 6 12:32 word.h
Just type make to have your application built:
$ make
gcc -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast -c -o word.o word.c
gcc -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast -c -o line.o line.c
gcc -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast -c -o justify.o justify.c
gcc -o justify word.o line.o justify.o -Wall -Wextra -pedantic -finline-functions -std=c11 -Wshadow -Ofast
strip -s justify
No errors, you can check all files were created as expected:
$ ll
total 44
-rw-r--r-- 1 david david 668 Nov 6 12:38 Makefile
-rwxr-xr-x 1 david david 6312 Nov 6 13:01 justify
-rw-r--r-- 1 david david 161 Nov 6 12:31 justify.c
-rw-r--r-- 1 david david 1760 Nov 6 13:01 justify.o
-rw-r--r-- 1 david david 106 Nov 6 12:32 line.c
-rw-r--r-- 1 david david 37 Nov 6 12:31 line.h
-rw-r--r-- 1 david david 1496 Nov 6 13:01 line.o
-rw-r--r-- 1 david david 104 Nov 6 12:32 word.c
-rw-r--r-- 1 david david 36 Nov 6 12:32 word.h
-rw-r--r-- 1 david david 1496 Nov 6 13:01 word.o
Test your executable:
$ ./justifiy
I'm in the main.
read_word
write_line
Lastly, clean your build directory with make clean, e.g.
$ make clean
And confirm all build files are removed.
That's about the easiest way to go about writing minimal make files. You can list each object individually and the required includes to support them, but why? the automatic variables will take care of that for you. There is much, much more you can do with Makefiles, but for getting started, this will make your life easier.

You can heavily simplify the Makefile you have. Make provides lots of helpful variables.
$# - target name
$< - first prequisite
$^ - all prequsites
justify: justify.o line.o word.o
gcc -o $# $^ # this one will turn into
# gcc -o justify justify.o line.o word.o
justify.o: justify.c
gcc -c $< # this one will turn into
# gcc -c justify.c
line.o: line.c
gcc -c $<
word.o: word.c
gcc -c $<
it's also a good idea to add clean
clean:
-rm *.o justify
-rm - minus sign at the beginning will not produce error if command fails;
useful in case you expect that something might be missing

There is bug in your make file. The commands for the make target justify: are missing the output file name. It should be like this.
gcc -o justify justify.o line.o word.o
with your current command line the gcc will try to output justify.o by linking line.o and word.o and the it does not find _main which is not defined in line.o and word.o
The make command already knows how to convert a .c file to .o so you do not need to tell this to make again in the make file. Keeping this in mind, the following make file is enough for your test case.
# Makefile
justify: justify.o line.o word.o
gcc -o justify justify.o line.o word.o
You can further simplify this by using make's built-in automatic variables. $# and $^. The $# variable contains the name of the target of rule. and $^ contains the name of all the prerequisites of the rule. So using these two variables your make file will be.
justify: justify.o line.o word.o
gcc -o $# $^

Related

Makefile with files in different folders

I'm new with makefiles and I'm trying to write one that compiles files from different folders. You can see my files distribution in the output of tree command that I have added to the post:
I want my header files in the includes folder, some library files in srclib, my main source files in src and the generated .o in lib. To start, I have tried recursive makefiles but I'm unable to compile tcp.c because the compiler can't find tcp.h, I'm stuck.
Output tree command
.
|-- includes
| `-- tcp.h
|-- lib
|-- makefile
|-- src
| |-- cliente.c
| `-- servidor_preforked.c
`-- srclib
`-- tcp.c
you need to indicate where to find the header to your compiler, for gcc this is done with the option -I
For instance if you produce a.out in lib your makefile can be :
lib/a.out:
gcc -o lib/a.out -I includes srclib/tcp.c src/cliente.c src/servidor_preforked.c
To also produces objects in lib :
all::lib/a.out
GCC = gcc -ansi -pedantic -Wextra
lib/tcp.o : srclib/tcp.c includes/tcp.h
$(GCC) -c -o lib/tcp.o -I includes srclib/tcp.c
lib/cliente.o : src/cliente.c includes/tcp.h
$(GCC) -c -o lib/cliente.o -I includes src/cliente.c
lib/servidor_preforked.o : src/servidor_preforked.c includes/tcp.h
$(GCC) -c -o lib/servidor_preforked.o -I includes src/servidor_preforked.c
lib/a.out : lib/tcp.o lib/cliente.o lib/servidor_preforked.o
$(GCC) -o lib/a.out -I includes lib/tcp.o lib/cliente.o lib/servidor_preforked.o
Example :
pi#raspberrypi:/tmp/d $ rm lib/*
pi#raspberrypi:/tmp/d $ make
gcc -ansi -pedantic -Wextra -c -o lib/tcp.o -I includes srclib/tcp.c
gcc -ansi -pedantic -Wextra -c -o lib/cliente.o -I includes src/cliente.c
gcc -ansi -pedantic -Wextra -c -o lib/servidor_preforked.o -I includes src/servidor_preforked.c
gcc -ansi -pedantic -Wextra -o lib/a.out -I includes lib/tcp.o lib/cliente.o lib/servidor_preforked.o
pi#raspberrypi:/tmp/d $ ls -l lib
total 24
-rwxr-xr-x 1 pi pi 8208 févr. 23 18:15 a.out
-rw-r--r-- 1 pi pi 956 févr. 23 18:15 cliente.o
-rw-r--r-- 1 pi pi 856 févr. 23 18:15 servidor_preforked.o
-rw-r--r-- 1 pi pi 840 févr. 23 18:15 tcp.o
Yes, you can explicitly add folder names to targets and commands as #bruno, but that's a bit like hardcoding, plus adds a bit of duplication. A way to improve that is to use VPATH or vpath function that fits for that case:
vpath %.h includes
vpath %.c src:srclib
vpath %.o lib
This tells which directory to search for a particular type of files. For .c files it will search both "src" and "srclib".
Now the rules might look simpler like so:
cliente.o : cliente.c tcp.h
$(GCC) -c -o lib/$# -I includes $<
Note the usage of $# and $< automatic variables. In this case $< will expand to the first prerequisite path with directory - "lib/cliente.c", and $# is just the target name - "cliente.o".
If you write the rules like so you might end up that all your rules look the same, and think about refactoring it further to just a single implicit pattern rule %.o: %.c.

No debugging symbols found in ArchLinux with -g

I have a problem with GDB in Archlinux:
Even I add -g in my Makefile gdb say (no debugging symbols found)...done..
But if I compile manually gcc -g *.c it work...
I don't know what is don't work in my Makefile ?
My Archlinux:
Linux sime_arch 4.13.4-1-ARCH #1 SMP PREEMPT Thu Sep 28 08:39:52 CEST 2017 x86_64 GNU/Linux
My GCC:
gcc version 7.2.0 (GCC)
My Makefile:
SRC = test.c \
test2.c
OBJ = $(SRC:.c=.o)
NAME = test_name
CFLAG = -Wall -Werror -Wextra
all: $(NAME)
$(NAME): $(OBJ)
gcc -g $(OBJ) -o $(NAME) $(CFLAG)
clean:
rm -f $(OBJ)
fclean: clean
rm -f $(NAME)
re: fclean all}
Thanks in advance
You are adding the -g only to the linking command. The object files are generated by the auto compile target of make. This doesn't have the -g flag in it.
You have 2 options -
Change your variable CFLAG to CFLAGS and add -g to it. CFLAGS is picked by the auto compile command and it will create object files with debug info
Add the following target -
%.o: %.c
gcc -g $(CFLAG) -o $# $<
before the $(NAME) target.
The second one gives you more control with the targets but the first method is the standard way of compiling.
Also, always try using standard names for variables unless you specifically need to name them separately.

Makefile issue - No rule to make target 'gcc'

I have just started learning make and I am having some trouble. I want to create an executable called sortfile. Here are the relevant files: sortfile.c fileio.c fileio.h
Both sortfile.c and fileio.c use fileio.h.
Here is my makefile:
1 CC = gcc
2 CFLAGS = -g -Wall
3
4 default: sortfile
5
6 sortfile: sortfile.o fileio.o $(CC) $(CFLAGS) -o sortfile sortfile.o fileio.o
7
8 sortfile.o: sortfile.c fileio.h $(CC) $(CFLAGS) -c sortfile.c
9
10 fileio.o: fileio.c fileio.h $(CC) $(CFLAGS) -c fileio.c
11
12 clean:
13 $(RM) sortfile *.o*~
I am getting the following error:
make: *** No rule to make target `gcc', needed by `sortfile.o'. Stop.
Makefiles are of the format:
target: dependency1 dependency2
rule (command to build)
You listed the command as the set of dependencies, so make wants to try to build gcc before it can expect sortfile.o to be satisfied.
Instead of:
sortfile.o: sortfile.c fileio.h $(CC) $(CFLAGS) -c sortfile.c
you need:
sortfile.o: sortfile.c fileio.h
$(CC) $(CFLAGS) -c sortfile.c
Note that normally all you really want here is something much simpler:
CFLAGS+=-g -Wall
all: sortfile
sortfile: sortfile.o fileio.o
This brief Makefile will work as expected with GNU Make because of implicit rules (see also).

Updated: How to invoke makefile of a child directory to create a consolidate .o file which can be linked :

I have a root directory and a child directory. I am planning to put the functions in child directory under libfunc.o
This libfunc.o should be merged along with other object files in top directory. But I am getting error:
$make all
cd folder; make libfunc.o
make[1]: Entering directory `/home/Work/test_makefile/folder'
cc -c -o func2.o func2.c
cc -c -o func3.o func3.c
func3.c: In function ‘set’:
func3.c:3:25: warning: initialization makes pointer from integer without a cast [enabled by default]
ld -r -o libfunc.o func2.o func3.o
make[1]: Leaving directory `/home/Work/test_makefile/folder'
arm-linux-gnueabi-gcc -c -o hellofun.o hellofun.c -I. -I./include
arm-linux-gnueabi-gcc -c -o hellomake.o hellomake.c -I. -I./include
arm-linux-gnueabi-gcc hellofun.o hellomake.o folder/libfunc.o -o hm
folder/libfunc.o: file not recognized: File format not recognized
collect2: ld returned 1 exit status
make: *** [hm] Error 1
Makefiles: toplevel
1 CC=arm-linux-gnueabi-gcc
2 LD=arm-linux-gnueabi-ld
3 AR=arm-linux-gnueabi-ar
4 CFLAGS=-I. -I./include
5 SOURCES=hellofun.c hellomake.c
6 OBJECTS=$(SOURCES:.c=.o)
7 SUBDIR_OBJS=folder/libfunc.o
8 TARGET=hm
9 DEPS = hellomake.h
10
11 %.o: %.c $(DEPS) $(SUBDIR_OBJS)
12 $(CC) -c -o $# $< $(CFLAGS)
13
14 folder/libfunc.o:
15 cd folder; $(MAKE) libfunc.o
16
17 clean:
18 rm -rf *.o hellomake folder/*.o
19
20 all: $(SOURCES) $(TARGET)
21
22 $(TARGET): $(OBJECTS)
23 $(CC) $(OBJECTS) $(SUBDIR_OBJS) -o $#
24
Makefile : Child
1 SOURCES=$(wildcard *.c)
2 OBJECTS=$(SOURCES:.c=.o)
3 TARGET=libfunc.o
4 %.o: %.c
5 $(CC) -c -o $# $< $(CFLAGS)
6
7 clean:
8 rm -rf *.o
9
10
11 $(TARGET): $(OBJECTS)
12 $(if $(strip $(OBJECTS)),\
13 $(LD) $(LDFLAGS) -r -o $# $(OBJECTS),\
14 rm -f $#; $(AR) rcs $# )
~
~
~
There's more than one error here. First, when asking questions please always provide the complete error message. The no rule to make target error will print out which target it's trying to make; that's critical information for helping you.
Second, you reference a variable SUBDIR_OBJS, but that's never defined. Plus you list that as a prerequisite for building other object files in the %.o : %.c rule: it's virtually never correct to list object files as prerequisites of other object files.
The top-level makefile does not run make in the folder directory, so no commands in that directory will be run automatically. You'll have to go there and run make yourself by hand.
Also in config.mk you create a variable merge_object but in folder/Makefile you refer to a variable merge_objects, which is not the same variable.
I missed export CC in root makefile
I would suggest put on the -Wall option in your compiler options, so that you can have a better debug view of your compiling process.
The output ld -r -o libfunc.o func2.o func3.o seems suspicious to me. Looks like The system used default linker rather than your cross-compile linker, which is arm-linux-gnueabi-ld. That might be a reason for the file not recognized.
As the error was file format not recognized, maybe you can check file libfunc.o output?
If you are having with LD, why not skip it and try other methods, like just gcc -o hm with all object files, or use ar to package the objects in subfolder.

Makefile for a library

I have to run these 4 commands on the terminal each time I want to execute the program using libraries.
The lines are
cc -m32 -c mylib.c
ar -rcs libmylib.a mylib.o
cc -m32 -c prog.c
cc -m32 prog.o -L. -lmylib
./a.out
How do I make a makefile for the above commands and run it?
A detailed procedure would be appreciated. Thanks.
Edit:
Here is the solution:
a.out: prog.o libmylib.a
cc prog.o -L. -lmylib
prog.o: prog.c mylib.h
libprint_int.a: mylib.o
ar -rcs libmylib.a mylib.o
print_int.o: mylib.c mylib.h
clean:
rm a.out prog.o libmylib.a mylib.o
This gave an error on line 2 because I used spaces instead of tab.
Something like:
program_NAME := a.out
SRCS = mylib.c prog.c
.PHONY: all
all: $(program_NAME)
$(program_NAME): $(SRCS)
ar -rcs libmylib.a mylib.o
cc -m32 prog.o -L. -lmylib
might get you started
only just started using makefiles myself and I think they are pretty tricky but once you get them working they make life a lot easier (this ones prob full of bugs but some of the more experienced SO folk will prob be able to help fix them)
As for running, make sure you save the file as 'Makefile' (case is important)
then from the cmd line (ensure you cd to the dir containing the Makefile):
$ make
thats it!
UPDATE
if the intermediate static library is superfluous you could skip it with a Makefile like this:
program_NAME := a.out
SRCS = mylib.c prog.c
OBJS := ${SRCS:.c=.o}
CFLAGS += -m32
program_INCLUDE_DIRS :=
program_LIBRARY_DIRS :=
program_LIBRARIES := mylib
CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))
CC=cc
LINK.c := $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
.PHONY: all
all: $(program_NAME)
$(program_NAME): $(OBJS)
$(LINK.c) $(program_OBJS) -o $(program_NAME)
I think there is no more detailed procedure than the official documentation of the make command: http://www.gnu.org/software/make/manual/make.html#Overview
Basically you will have to create a target and just put your commands in it. The target could be 'all' if you want it to work when you type 'make'. A good makefile will surely use variables etc to keep it flexible over the lib/sources additions.
The simplest tutorial to understand make files is available in Cprogramming.com. Once you are through with understanding it then you can go though the make file manual.

Resources