I have these sources and headers. How do I make a make file for them?
//a.h
#ifndef A_H
#define A_H
#include <stdio.h>
int fun(int i);
#endif
//a.c
#include "a.h"
int fun(int i){
if(i%2==0){
return 1;
}
printf("%d\n",i);
}
//b.h
#ifndef B_H
#define B_H
#include "a.h"
int fun2(int i);
#endif
//b.c
#include "b.h"
#include <stdio.h>
int fun2(int i){
if(i%2==0){
return 1;
}
printf("%d\n",fun(2));
}
//c.c
#include "b.h"
#include <stdio.h>
int main(){
int a=1;
a=fun(1);
printf("%d %d\n",a,fun(1));
int b=1;
b=fun2(2);
printf("%d %d\n",b,fun2(1));
}
This is the makefile I have created:
//makefile
CC=gcc
all:main
main: c.c b.o
$(CC) c.c b.o -o $#
b.o: b.c a.o
cc -c b.c a.o
a.o: a.c
cc -c a.c
.PHONY:clean
clean:
rm -rf *.o
rm -rf main
b.c use function fun() defined in a.h (and therefore, fun() is declared in a.c).
c.c uses functions fun() from a.h and fun2() in b.h.
a.h is already included in b.h and I am including b.h in c.c.
Therefore, I have not included a.h again in c.c.
I am trying to make .o files of all of these a.c b.c and c.c, and then link them into a executable named main.
First, trying to combine two source files (like a.c and b.c) into a single object file is unusual, awkward and pointless. Just build an object for every source; if you like, you can combine them into a library later.
b.o: b.c
cc -c b.c
Second, you're using object files (which is a good idea), so use object files. Don't make c an exception.
main: a.o b.o c.o
$(CC) a.o b.o c.o -o $#
Third, Make already has an implicit rule for building object files from C source files, so you don't have to write those rules,
Fourth and last, there are more automatic variables than just $#, and they're good tools to know:
main: a.o b.o c.o
$(CC) $^ -o $#
These are the files after edit, now the makefile works fine:
//a.h
#ifndef A_H
#define A_H
#include <stdio.h>
int fun(int i);
#endif
//a.c
#include "a.h"
int fun(int i){
if(i%2==0){
return 1;
}
printf("%d\n",i);
}
//b.h
#ifndef B_H
#define B_H
#include "a.h" //included a.h as fun2() uses fun() in a.h
int fun2(int i);
#endif
//b.c
#include "b.h"
#include <stdio.h>
int fun2(int i){
if(i%2==0){
return 1;
}
printf("%d\n",fun(2));
}
//c.c
#include "b.h" //b.h becauses fun2() in this, and a.h is in this header, explanation in b.h
#include "a.h" //I have now included a.h also as this uses fun(), multiple inclusions don't matter as these headers have include guards
#include <stdio.h>
int main(){
int a=1;
a=fun(1);
printf("%d %d\n",a,fun(1));
int b=1;
b=fun2(2);
printf("%d %d\n",b,fun2(1));
}
I don't need .c files or definitions of external functions I use in something.c, I just need their headers (or declarations) to create .o (object files).
Therefore, to create, b.o from b.c, I have included a.h and b.h for function definitions and gcc -c b.c creates b.o
Similarly, c.o is made using gcc -c c.c , I have included a.h and b.h in c.c as I use their functions.
lastly, just link them together, gcc -o main a.o b.o c.o
This is the new make file, I ws making it wrong, was including .c of the external function while making their .o, this time I just include headers and do gcc -c a.c, b.c or c.c (separately for these 3), after this I link a.o b.o c.o to make a dynamically linked exec named main:
CC=gcc
all:main
main: a.o b.o c.o
$(CC) $^ -o $#
c.o: c.c a.h b.h
cc -c $<
b.o: b.c b.h a.h
cc -c $<
a.o: a.c a.h
cc -c $<
.PHONY:clean
clean:
rm -rf *.o
rm -rf main
This is the output of make:
─# make
cc -c a.c
cc -c b.c
cc -c c.c
gcc a.o b.o c.o -o main
I did nm on these .o files, and figured out the undefined functions marked by U.
─#nm a.o
0000000000000000 T fun
U printf
─#nm b.o
U fun
0000000000000000 T fun2
U printf
─#nm c.o
U fun
U fun2
0000000000000000 T main
U printf
The symbols marked with U are undefined.In b.o fun() is marked U as it is in a.o.
I tried combining them with ld:
─#ld -relocatable a.o b.o -o ab.o
─# ls ab.o
ab.o
─# file !:1
file ab.o
ab.o: ELF 64-bit LSB relocatable, ARM aarch64, version 1 (SYSV), not stripped
─# nm ab.o
0000000000000000 T fun
000000000000003c T fun2
U printf
//This ab.o has fun defined, and is therefore marked with T
─# ld -relocatable ab.o c.o -o abc.o
─# nm abc.o
0000000000000000 T fun
000000000000003c T fun2
0000000000000080 T main
U printf
//fun, fun2 are marked with T in abc.o, they were U in c.o
─# gcc abc.o -o abc
─# ./abc
1
1
2 2
1
1 2
Makefile isn't using implicit rules correctly. I am following this guide here.
Here's my makefile:
objects = main.o hello.o
hello : $(objects)
cc -o hello $(objects)
hello.o : defs.h
main.o : defs.h hello.h
.PHONY : clean
clean :
-rm hello $(objects)
I get the following error:
cc: error: main.o: No such file or directory
It creates the object code hello.o, but does not do it for main.c. If I swap lines and main is above, it'll create main.o but not hello.o.
Here's my main.c file:
#include "defs.h"
#include "hello.h"
int main(int argc, char** argv) {
display_hello();
return (EXIT_SUCCESS);
}
Here's my hello.c file:
#include "defs.h"
void display_hello()
{
printf("Hello!\n");
}
My hello.h file:
#ifndef HELLO_H
#define HELLO_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* HELLO_H */
void display_hello();
Here's my defs.h file:
#ifndef DEFS_H
#define DEFS_H
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
#endif /* DEFS_H */
#include <stdio.h>
#include <stdlib.h>
Works fine for me, I created the files as https://gist.github.com/boyvinall/f23420215707fa3e73e21c3f9a5ff22b
$ make
cc -c -o main.o main.c
cc -c -o hello.o hello.c
cc -o hello main.o hello.o
Might be the version of make like #Beta said, but even an old version of GNU make should work just fine for this.
Otherwise, ensure you're using tabs to indent in the makefile, not spaces.
I am executing a simple makefile that contait 3 parts but it does not work well these are details of my files .h and .c:
main.c
#include <stdio.h>
#include <stdlib.h>
#include "hello.h"
int main (void)
{
hello();
return EXIT_SUCCESS;
}
hello.h
#ifndef hello
#define hello
void hello (void);
#endif
hello.c
#include <stdio.h>
#include <stdlib.h>
void hello (void)
{
printf("Hello World\n");
}
makefile
all: hello
hello: hello.o main.o
gcc -o hello hello.o main.o
hello.o: hello.c
gcc -o hello.o -c hello.c -W -Wall -ansi -pedantic
main.o: main.c hello.h
gcc -o main.o -c main.c -W -Wall -ansi -pedantic
clean:
rm -rf *.o
mrproper: clean
rm -rf hello
I get this error:
When you write #define hello you define hello to be an empty token. Thus the function declaration on the next string effectively becomes this:
void (void);
which is not valid C code.
What you are trying to do is probably the Include guard, its purpose is to avoid multiple inclusion of one header. The name of the guard have to differ from any other token you use. Usual naming is FILENAME_H:
#ifndef HELLO_H
#define HELLO_H
void hello(void);
#endif
In hello.h, line 2 you are defining 'hello' as an empty token. Remove that line.
Here's the directory structure for my setup:
Matrix
│ Makefile
│
├───bin
├───include
│ matrix.h
│
├───lib
├───obj
├───rc
│ matrix.rc
│
└───src
matrix.c
matrix_mem.c
Here's the Makefile:
# This Makefile will build the Matrix Library.
TOOLCHAIN := C:\MinGW
SRCTREE := C:\Users\admin\Desktop\Matrix\Matrix
CC := $(TOOLCHAIN)\bin\gcc.exe
AR := $(TOOLCHAIN)\bin\ar.exe
WINDRES := $(TOOLCHAIN)\bin\windres.exe
SRCDIR := $(SRCTREE)\SRC
OUTDIR := $(SRCTREE)\BIN
OBJDIR := $(SRCTREE)\OBJ
RESDIR := $(SRCTREE)\RC
LIBDIR := $(SRCTREE)\LIB
INCDIR := $(SRCTREE)\INCLUDE
CFLAGS := -O3 -std=gnu89 -Wall
CFLAGS_EXTRA :=
OBJS := $(shell find $(OBJDIR) -name '*.o')
DEPS := $(OBJS:.o=.d)
-include $(DEPS)
all: dll
dll: CFLAGS_EXTRA := -DMATRIX_USE_DLL -DDLL_EXPORTS
dll: matrix.dll
static: CFLAGS_EXTRA :=
static: matrix.lib
matrix.dll: matrix_mem.o matrix.o resource.o
matrix.lib: matrix_mem.o matrix.o
%.o: $(SRCDIR)\%.c
$(CC) $(CFLAGS) -I $(INCDIR) $(CFLAGS_EXTRA) -MM -MT $(OBJDIR)\$# -MF $(patsubst %.o,%.d,$(OBJDIR)\$#) $<
$(CC) -c $(CFLAGS) -I $(INCDIR) $(CFLAGS_EXTRA) -o $(OBJDIR)\$# $<
#echo ...$(OBJS)...
%.dll:
$(CC) -shared -s -o $(OUTDIR)\$# $(patsubst %,$(OBJDIR)\\%,$^) -Wl,--subsystem,windows,--output-def,$(OUTDIR)\$*.def,--out-implib,$(OUTDIR)\$*.lib
%.lib:
$(AR) -ru $(OUTDIR)\$# $(patsubst %,$(OBJDIR)\\%,$^)
resource.o: $(RESDIR)\matrix.rc
$(WINDRES) -i $< -o $(OBJDIR)\$#
clean::
-rm $(OBJDIR)\matrix.o
-rm $(OBJDIR)\matrix_mem.o
-rm $(OBJDIR)\matrix.d
-rm $(OBJDIR)\matrix_mem.d
-rm $(OBJDIR)\resource.o
-rm $(OUTDIR)\matrix.def
-rm $(OUTDIR)\matrix.lib
-rm $(OUTDIR)\matrix.dll
The Makefile works ok under MinGW and Cygwin.
I'm still having difficulties in getting the include dependency to work.
It appears that the .d files are not getting included. Since the code compiles fine across GCC variants, I was wanting to try to compile it on Linux. I want to make minimum changes to the Makefile.
I understand that I'll have to change the path styles and other compile options.
But, as of here, how can I get make to treat include dependencies correctly, without much intertwining with the shell? I'm using make 3.80 version.
Here's a minimal source implementation:
matrix.h:
/*----------------------------- matrix.h ------------------------------*/
#ifndef __MATRIX_H_INCLUDED__
#define __MATRIX_H_INCLUDED__
#ifdef _WIN32
#ifdef MATRIX_USE_DLL
#ifdef DLL_EXPORTS
#define MATRIX_API __declspec(dllexport)
#else
#define MATRIX_API __declspec(dllimport)
#endif
#else
#define MATRIX_API
#endif
#define MATRIX_CALL __stdcall
#else
#define MATRIX_API
#define MATRIX_CALL
#endif
#ifdef __cplusplus
extern "C" {
#endif
typedef struct _Matrix {
double **data;
int m;
int n;
} Matrix;
MATRIX_API void MATRIX_CALL dummy_func2();
MATRIX_API void MATRIX_CALL dummy_func2();
#ifdef __cplusplus
}
#endif
#endif
/*---------------------------------------------------------------------*/
matrix.c:
/*----------------------------- matrix.c ------------------------------*/
#include "matrix.h"
MATRIX_API void MATRIX_CALL dummy_func1() {
return;
}
/*---------------------------------------------------------------------*/
matrix_mem.c:
/*--------------------------- matrix_mem.c ----------------------------*/
#include "matrix.h"
MATRIX_API void MATRIX_CALL dummy_func2() {
return;
}
/*---------------------------------------------------------------------*/
Where am I going wrong; I want to define a preprocessor value on the command-line for g++ but it fails. Below is sample code that replicate my problem:
[edit] I'm using:g++ (Debian 4.3.2-1.1) 4.3.2GNU Make 3.81
test.h
#ifndef _test_h_
#define _test_h_
#include "iostream"
#if defined(MY_DEFINED_VALUE)
#if (MY_DEFINED_VALUE != 5)
#undef MY_DEFINED_VALUE
#define MY_DEFINED_VALUE 3
#endif //(MY_DEFINED_VALUE != 5)
#else //defined(MY_DEFINED_VALUE)
#error Error - MY_DEFINED_VALUE is not defined
#endif //defined(MY_DEFINED_VALUE)
class test
{
public:
int val;
test() {}
void show() { std::cout << "val = " << val << "\n"; }
};
#endif //_test_h_
test.cpp
//#define MY_DEFINED_VALUE 5
#include "test.h"
int main()
{
test t;
t.val = MY_DEFINED_VALUE;
t.show();
return 0;
}
Makefile
#=====
CC = g++
LD = g++
USERDEFINES = -DMY_DEFINED_VALUE
CFLAGS = -Wall
LDFLAGS =
RM = /bin/rm -f
SRCS = test.cpp
OBJS = test.o
PROG = test
#=====
$(PROG): $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) -o $(PROG)
#=====
%.o: %.c
$(CC) $(USERDEFINES) $(CFLAGS) -c $<
#=====
clean:
$(RM) $(PROG) $(OBJS)
If I uncomment the #define in test.cpp, all is well (prints 5). If I comment it I get the #error.
The problem is in your Makefile. The %.o: %.c rule doesn't match a .cpp file, so GNU Make's built-in %.o: %.cpp rule is being triggered instead.
If you change %.o: %.c to %.o: %.cpp, it'll run fine.