Makefile for beginners - c

I just started learning about makefiles: i created a simple tutorial by myself but it seems I am mistaken somewhere and i don't know where; my mini-tutorial is formed by a main.c script that recalls a function named kernel.c; within this last function 2 more functions are called: add.c (which adds 2 numbers together) and mul.c (which multiplies the result of the previous sum); i then created the headers kernel.h and functions.h which contain the prototypes of the functions defined above; this two header are contained in a folder created within the same one of the main.c script: common/inc
Here are the files:
//main
#include <stdio.h>
#include <stdlib.h>
#include "kernel.h"
int main(){
int a = 5, b = 4, c = 0;
int *pa, *pb, *pc;
pa = &a; pb = &b; pc = &c;
kernel(pa, pb, pc);
printf("c = %d\n", c);
return 0;
}
here is kernel.c
#include "kernel.h"
#include "functions.h"
void kernel(int* a, int*b, int* c){
int x = add(*a,*b);
*c = mul(x);
}
here is add.c
#include "functions.h"
int add(int a, int b){
return a + b;
}
here is mul.c
#include "functions.h"
int mul(int a){
return a*2;
}
here is kernel.h
void kernel(int* a, int*b, int* c);
here is functions.h
int add(int a, int b);
int mul(int a);
The make file i wrote looks like this:
#===========================Makefile================================#
CC=gcc
IDIR = common/inc
CFLAGS=-c -Wall -I$(IDIR)
all: eseguibile
eseguibile: main.o
$(CC) $(CFLAGS) main.o -o eseguibile
main.o: main.c kernel.o
$(CC) $(CFLAGS) main.c kernel.o
kernel.o: kernel.c add.o mul.o
$(CC) $(CFLAGS) kernel.c add.o mul.o
add.o: add.c
$(CC) $(CFLAGS) add.c
mul.o: mul.c
$(CC) $(CFLAGS) mul.c
clean:
rm -rf *o eseguibile
I know the program works because if i type gcc main.c kernel.c add.c mul.c -I common/inc/ in the terminal everything works fine.
Can anyone tell me what I a doing wrong?`
The error that i get is this:
gcc -c -Wall -Icommon/inc add.c
gcc -c -Wall -Icommon/inc mul.c
gcc -c -Wall -Icommon/inc kernel.c add.o mul.o
gcc: warning: add.o: linker input file unused because linking not done
gcc: warning: mul.o: linker input file unused because linking not done
gcc -c -Wall -Icommon/inc main.c kernel.o
gcc: warning: kernel.o: linker input file unused because linking not done
gcc -c -Wall -Icommon/inc main.o -o eseguibile
gcc: warning: main.o: linker input file unused because linking not done

I prefer to build the objects separately, and then combine them all at the end. I think the problem is that you are including a -c flag on the final executable. Try this:
#===========================Makefile================================#
CC=gcc
IDIR = common/inc
CFLAGS=-Wall -I$(IDIR)
OBJS = main.o kernel.o add.o mul.o
all: eseguibile
eseguibile: $(OBJS)
$(CC) $(CFLAGS) $^ -o eseguibile
main.o: main.c kernel.h
$(CC) -c $(CFLAGS) main.c
kernel.o: kernel.c kernel.h functions.h
$(CC) -c $(CFLAGS) kernel.c
add.o: add.c functions.h
$(CC) -c $(CFLAGS) add.c
mul.o: mul.c functions.h
$(CC) -c $(CFLAGS) mul.c
clean:
rm -rf *.o eseguibile

Related

Getting a C error that I have an undefined reference to function, but the function is defined

I am trying to take a binary to decimal function out of my main.c file and into its own file, but when I compile the files with my makefile I get the error:
undefined reference to `btod'
Here is my main.c file:
#include "btod.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int n;
printf("\nEnter a binary number: ");
char c[100];
scanf("%s",c);
printf("Number converted to decimal: %d\n\n\n",btod(strlen(c),c));
return 0;
}
Here is my btod.c file:
#include <stdlib.h>
#include <string.h>
int btod(int size,char inputBin[size])
{
int i,num=0;
for(i=0;i<size;i++)
{
num=num*2+(inputBin[i]-48);
}
return num;
}
Here is my btod.h file:
int btod(int size,char inputBin[size]);
And lastly, here is my makefile:
CC = gcc
INCLUDE = -I.
CFLAGS = -g -Wall
LDFLAGS = -L. \
-L/usr/lib
LDLIBS = \
-lc -lm
.c.o:
$(CC) $(INCLUDE) $(CFLAGS) -c $<
all: main
main: main.o
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
btod: btod.o
$(CC) -o $# $^ $(LDFLAGS) $(LDLIBS)
clean:
rm -f *.o
rm -f main
I am thinking it might have to do with the btod.c file not being compiled properly within the makefile but I cannot figure out what is incorrect about it.
The error is because you don't link in btod.o when building main. If you use GNU Make, you can simplify your Makefile to just a few lines:
.PHONY: all clean
CFLAGS = -g -Wall
all: main
clean:
rm -f *.o main
main: btod.o main.o
In btod.c use '0' instead of 48. In main.c remove the line int n.

How to link multiple .c files

I know that you have to create a header file and #include it in your main. I have done that and when I compile my code for some reason it is unable to figure out where one of my functions are.
The layout of my project is a: threads.c makeCityFromInput.h and makeCityFromInput.c
I have the threads.c #including the makeCityFromInput.h
This is what happens when I try to compile:
make
gcc -ggdb -std=c99 -Wall -Wextra -pthread -c threads.c
gcc -ggdb -std=c99 -Wall -Wextra -pthread -o threads threads.o -lm -lncursesw -pthread
threads.o: In function `main':
/home/project3/threads.c:183: undefined reference to `readConfig'
collect2: error: ld returned 1 exit status
Makefile:71: recipe for target 'threads' failed
make: *** [threads] Error 1
It is unable to find my readconfig file even though it is in my header file
my threads.c file
#define _DEFAULT_SOURCE
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <ncurses.h> //displays the cars
#include <pthread.h> //threading
#include <unistd.h>
#include "makeCityFromInput.h"
#define MAX 2048
int main(int argc, char *argv[]){
//Expected input: Name of config file
// If the config file is not given; or too many config files are given
if (argc != 2){
endwin();
fprintf(stderr, "Usage: Enter a configuration file");
exit( EXIT_FAILURE );
}
FILE *fp = NULL;
fp = fopen(argv[1], "r");
assert( fp );
readConfig(fp);
fclose( fp );
return 0;
}
my makeCityFromInput.h file:
#ifndef _MAKECITYFROMINPUT_H
#define _MAKECITYFROMINPUT_H
void readConfig(FILE *fp);
int *parse_line(char *line, int *numInts);
void create_skyline(int *ground, int size, int maxMissiles);
#endif
my makeCityFromInput.c file:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <strings.h>
#include <string.h>
#include <ncurses.h> //displays the cars
#include <pthread.h> //threading
#include <unistd.h>
void readConfig(FILE *fp){
...
}
My make file
#
# Created by gmakemake (Ubuntu Jul 25 2014) on Wed Nov 14 20:05:05 2018
#
#
# Definitions
#
.SUFFIXES:
.SUFFIXES: .a .o .c .C .cpp .s .S
.c.o:
$(COMPILE.c) $<
.C.o:
$(COMPILE.cc) $<
.cpp.o:
$(COMPILE.cc) $<
.S.s:
$(CPP) -o $*.s $<
.s.o:
$(COMPILE.cc) $<
.c.a:
$(COMPILE.c) -o $% $<
$(AR) $(ARFLAGS) $# $%
$(RM) $%
.C.a:
$(COMPILE.cc) -o $% $<
$(AR) $(ARFLAGS) $# $%
$(RM) $%
.cpp.a:
$(COMPILE.cc) -o $% $<
$(AR) $(ARFLAGS) $# $%
$(RM) $%
CC = gcc
CXX = g++
RM = rm -f
AR = ar
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS)
LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS)
COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) -c
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c
CPP = $(CPP) $(CPPFLAGS)
########## Flags from header.mak
CFLAGS = -ggdb -Wall -Wextra -pedantic -std=c99 -pthread
# program uses pthreads and curses libraries
CLIBFLAGS = -lncursesw -lpthread -lrt
########## End of flags from header.mak
CPP_FILES =
C_FILES = pt-cruisers.c racer.c
PS_FILES =
S_FILES =
H_FILES = racer.h
SOURCEFILES = $(H_FILES) $(CPP_FILES) $(C_FILES) $(S_FILES)
.PRECIOUS: $(SOURCEFILES)
OBJFILES = racer.o
#
# Main targets
#
all: pt-cruisers
pt-cruisers: pt-cruisers.o $(OBJFILES)
$(CC) $(CFLAGS) -o pt-cruisers pt-cruisers.o $(OBJFILES) $(CLIBFLAGS)
#
# Dependencies
#
pt-cruisers.o: racer.h
racer.o: racer.h
#
# Housekeeping
#
Archive: archive.tgz
archive.tgz: $(SOURCEFILES) Makefile
tar cf - $(SOURCEFILES) Makefile | gzip > archive.tgz
clean:
-/bin/rm -f $(OBJFILES) pt-cruisers.o core
realclean: clean
-/bin/rm -f pt-cruisers
It looks like this
gcc -ggdb -std=c99 -Wall -Wextra -pthread -c threads.c
gcc -ggdb -std=c99 -Wall -Wextra -pthread -c makeCityFromInput.c
gcc -ggdb -std=c99 -Wall -Wextra -pthread -o threads threads.o makeCityFromInput.o -lm -lncursesw -pthread
If you show your make file we can also help with that...
I guess what you are actually asking is "What is wrong with my makefile?". As you have not provided it I can only take an educated guess. Here is a GNUmake snippet to build your program:
.PHONY: default
default: threads
CC := ...
LD := ...
CFLAGS := ...
LDFLAGS := ...
LIBS := ...
SRCS := threads.c makeCityFromInput.c
OBJS := $(SRCS:%.c=%.o)
$(OBJS): %.o: %.c
$(CC) $(CFLAGS) -o $# -c $<
threads: $(OBJS)
$(LD) $(LDFLAGS) -o $# $^ $(LIBS)

Forcing Orders in Makefile Dependencies

I need some help writing a GNU makefile. I have a C program "main.c", which is dependent on the value of "CONSTANT" defined in the file "constants.h".
"main.c"
#include <stdio.h>
#include "constants.h"
void work(void)
{
int array[CONSTANT];
for (int i = 0; i < CONSTANT; i++) {
printf("%d\n", i);
}
}
int main(int argc, char const* argv[])
{
printf("constant=%d\n", CONSTANT);
work();
return 0;
}
"constant.h"
#ifndef CONSTANTS_H
#define CONSTANTS_H
#define CONSTANT 4
#endif
What I'm trying to do here is to compile the program with different values for "CONSTANT". For example, "out1" is compiled with "CONSTANT=1" and with "make all", I should be able to produce all the variants ("out1", "out2" and "out4").
The problem is that "a.o" required by "main.c" also depends on the value of "CONSTANT". So "a.o" must be compiled after "sed%". However, as far as I understand, there is no way in "make" to force orders in dependencies (I guess this is the whole point of using makefiles).
What is the recommended way to address this situation?
"Makefile"
CC= gcc
CFLAGS = -std=c99 -Wall
CONSTANTS = 1 2 4
targets = $(addprefix out, $(CONSTANTS))
seds = $(addprefix sed, $(CONSTANTS))
.PHONY: $(seds)
$(seds): sed%:
sed -i 's/define CONSTANT [0-9]*/define CONSTANT $*/g' constants.h
$(targets): out%: main.c sed% a.o
$(CC) $(CFLAGS) $< a.o -o $#
a.o: a.c constant.h
$(CC) $(CFLAGS) $< a.o -o $#
.PHONY: all
all : $(targets)
Note that I'm aware that I can rewrite "main.c" so that it takes a parameter from the comman line. In practice, many other files other than "main.c" depend on "CONSTANT", so I want to avoid rewriting all these files. I'm also aware that I can do something like "gcc -DCONSTANT=n main.c", but every file dependent on "CONSTANT" must be recompiled as well.
Related Questions
How to specify Makefile target building order without put any physical dependencies?
Force order of dependencies in a Makefile
I'm ... aware that I can do something like "gcc -DCONSTANT=n main.c",
but every file dependent on "CONSTANT" must be recompiled as well.
This needn't be a hindrance if you have your makefile generate
the correct -DCONSTANT=n and distinct object file in every compilation recipe.
Here's an illustration:
constants.h
#ifndef CONSTANTS_H
#define CONSTANTS_H
#ifndef CONSTANT
#define CONSTANT 4
#endif
#endif
foo.c
#include "constants.h"
int foo = CONSTANT;
main.c
#include <stdio.h>
#include "constants.h"
extern int foo;
int main()
{
printf("%d\n",CONSTANT + foo);
return 0;
}
Makefile
CC := gcc
CFLAGS := -std=c99 -Wall
CONSTANTS = 1 2 4
TARGETS = $(addprefix out, $(CONSTANTS))
SRCS := main.c foo.c
define compile =
$(basename $(1))$(2).o: $(1) constants.h
$$(CC) -c -DCONSTANT=$(2) $$(CFLAGS) $$< -o $$#
endef
.PHONY: all clean
all : $(TARGETS)
$(foreach src,$(SRCS),\
$(foreach const,$(CONSTANTS),$(eval $(call compile,$(src),$(const)))))
out%: main%.o foo%.o
$(CC) $^ -o $#
clean:
rm -f $(TARGETS) *.o
This runs like:
$ make
gcc -c -DCONSTANT=1 -std=c99 -Wall main.c -o main1.o
gcc -c -DCONSTANT=1 -std=c99 -Wall foo.c -o foo1.o
gcc main1.o foo1.o -o out1
gcc -c -DCONSTANT=2 -std=c99 -Wall main.c -o main2.o
gcc -c -DCONSTANT=2 -std=c99 -Wall foo.c -o foo2.o
gcc main2.o foo2.o -o out2
gcc -c -DCONSTANT=4 -std=c99 -Wall main.c -o main4.o
gcc -c -DCONSTANT=4 -std=c99 -Wall foo.c -o foo4.o
gcc main4.o foo4.o -o out4
And the resulting programs run like:
$ for i in 1 2 4; do ./out$i; done
2
4
8

Compiling: undefined reference to

I'm struggling with compiling multiple files into a common program. I'm getting an error:
undefined reference to 'pi'
Here's the skeleton of my code and Makefile. What am I doing wrong? Thanks!
File: calcPi.c
#include <stdlib.h>
#include <stdio.h>
#include <sched.h>
#include <string.h>
#include "pi.h"
int main(int argc, char* argv[]) {
long iterations = 1000000;
int policy = 2;
int numChildren = 3;
pi(iterations, policy, numChildren);
return 0;
}
File: pi.h
void pi(long iterations, int policy, int numChildren);
File: pi.c
#include "pi.h"
void pi(long iterations, int policy, int numChildren) {
//lots of code here
}
I'm compiling this using a Makefile:
CC = gcc
CFLAGS = -c -g -Wall -Wextra
LFLAGS = -g -Wall -Wextra
all: calcPi pi
calcPi: calcPi.o
$(CC) $(LFLAGS) $^ -o $# -lm
pi: pi.o
$(CC) $(LFLAGS) $^ -o $# -lm
calcPi.o: calcPi.c
$(CC) $(CFLAGS) $<
pi.o: pi.c
$(CC) $(CFLAGS) $<
clean:
rm -f pi calcPi
rm -f *.o
rm -f *~
EDIT: In response to the request for the entire error message:
In function 'main'"
calcPi.c:55: undefined reference to 'pi'
collect2: error: ld returned 1 exit status
make: * [calcPi.o] error 1
First of all, is pi really supposed to be a separate application?
You're referring the pi() function from calcPi, but it's only been compiled into pi.o, so you need to add it as a dependency.
What I think you want to do, is to create calcPi using the calcPi.o and pi.o object files.
CC = gcc
CFLAGS = -c -g -Wall -Wextra
LFLAGS = -g -Wall -Wextra
all: calcPi
calcPi: calcPi.o pi.o
$(CC) $(LFLAGS) $^ -o $# -lm
calcPi.o: calcPi.c
$(CC) $(CFLAGS) $<
pi.o: pi.c
$(CC) $(CFLAGS) $<
clean:
rm -f calc
rm -f *.o
rm -f *~

main.c:(.text+0x25): undefined reference to `reciprocal'

This is a sample program i was trying to compile this below c program to know about the
make file.
main.c
#include<stdio.h>
#include "reciprocal.h"
int main(int argc,char **argv){
int i;
i=atoi(argv[1]);
printf("The Reciprocal of %d is %f\n ",i,reciprocal(i));
return 0;
}
reciprocal.c
#include<stdio.h>
#include<assert.h>
#include "reciprocal.h"
double reciprocal(int i){
assert(i!=0);
return 1.0/i;
}
reciprocal.h
#include<stdio.h>
#ifdef __cplusplus
extern "C"{
#endif
extern double reciprocal(int i);
#ifdef __cplusplus
}
#endif
makefile
CFLAGS:=-o2
reciprocal: reciprocal.o main.o
gcc $(CFLAGS) -o reciprocal.o main.o
main.o: main.c reciprocal.h
gcc $(CFLAGS) -c main.c -I ../include
reciprocal.o: reciprocal.c reciprocal.h
gcc $(CFLAGS) -c reciprocal.c -I ../include
clean:
rm -f *.o reciprocal
when compiled as below it throws an error.
% make
gcc -o2 -c reciprocal.c -I ../include gcc -o2 -c main.c -I ../include
gcc -o2 -o reciprocal.o main.o main.o: In function main':
main.c:(.text+0x25): undefined reference toreciprocal' collect2: ld
returned 1 exit status make: * [reciprocal] Error 1
Please help me understand what is the reason for this error.
Change your makefile:
reciprocal: reciprocal.o main.o
gcc $(CFLAGS) -o reciprocal reciprocal.o main.o
^^^^^^^^^^
Alternatively:
reciprocal: reciprocal.o main.o
gcc $(CFLAGS) -o $# $^
You have an insidious typo:
CFLAGS:=-o2
That should have been -O2 with a capital O, this way you redirect the output of every compilation to the file 2.

Resources