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
I wrote a simple c++ code. I wanted to choose to execute one of the codes through the -D option of makefile, but it didn't execute? For example, code1 and code2.
1.main.cpp
#include "./common.h"
#include "./ns_api.h"
int TestFunc3(void)
{
}
int test = 10;
int main(int argv, char **argc)
{
extern int b;
int a = b;
printf("This is a test!\n");
#ifdef TEST_ADD
printf("test_add!\n"); //code1
#endif
#if TEST_SUB
printf("test_sub!\n"); //code2
#endif
return 0;
}
int b;
2.makefile
root#cat makefile
GPP = g++
CFLAGS += -O3
objects = *.o
src = *.cpp
test:$(objects)
$(GPP) $(CFLAGS) -o test $(objects)
$(objects):$(src)
$(GPP) -c $(src)
.PHONY:clean
clean:
rm test *.o
3.compile
root#make CFLAGS=-DTEST_ADD CFLAGS+=-DTEST_SUB=1
g++ -c *.cpp
g++ -DTEST_ADD -DTEST_SUB=1 -o test *.o
4.result:
root#./test
This is a test!
I'm trying to create a Makefile where make only recompiles necessary .cpp files.
By default, it works well if I edit .cpp, however, when I edit .h files, it just ignores the changes.
So I've read of -MD flag and its friend -MP (used to avoid bugs when typing make).
However, I can't seem to make it working, if I use -MMD, it works perfectly but I rely on system includes too as I'm writing a library too that is evolving along with the project. Thus, if I update the libary header and reinstall the library, typing make in the main project should recompiles files that includes the changed header.
When using -MMD flag, it - as expected - does not recompile the project, however, using -MD flag, it does recompile everything. In fact, -MD recompiles everything every time, even when nothing changed.
Here is a minimal project structure that reproduce the issue:
./Makefile:
all: build
re: clean build
build: build_lib install_lib build_client
build_lib:
$(MAKE) -C lib
$(MAKE) install -C lib
build_client:
$(MAKE) -C client
install_lib:
$(MAKE) install -C lib
.PHONY: clean
clean: clean_lib clean_client
clean_lib:
$(MAKE) clean -C lib
clean_client:
$(MAKE) clean -C client
./client/Makefile:
CC = g++
INC = -I../lib
CXXFLAGS = -Wall $(INC) -g -MD -MP
EXEC_NAME = ../test
src = $(shell find $(SOURCEDIR) -name '*.cpp')
obj = $(src:.cpp=.o)
LIBRARIES = -ltest_lib
LDFLAGS = -rdynamic $(LIBRARIES)
all: $(EXEC_NAME)
re: clean $(EXEC_NAME)
$(EXEC_NAME): $(obj)
$(CC) -o $# $^ $(LDFLAGS)
-include $(obj:.o=.d)
.PHONY: clean
clean:
rm -f $(obj) $(EXEC_NAME)
./lib/Makefile:
.PHONY : clean
CXXFLAGS= -fPIC -g -Itest_lib/include -MMD -MP
LDFLAGS= -shared
SOURCES = $(shell find $(SOURCEDIR) -name '*.cpp')
HEADERS = $(shell find $(SOURCEDIR) -name '*.h')
OBJECTS=$(SOURCES:.cpp=.o)
TARGET=libtest_lib.so
INC_FOLDER=test_lib/include
CUR_DIR = $(shell pwd)
all: $(TARGET)
install:
sudo rm -rf /usr/local/lib/libtest_lib.so && sudo ln -s $(CUR_DIR)/$(TARGET) /usr/local/lib/libtest_lib.so
sudo rm -rf /usr/local/include/test_lib && sudo cp -r $(INC_FOLDER) /usr/local/include/test_lib
clean:
rm -f $(OBJECTS) $(TARGET)
$(TARGET) : $(OBJECTS)
$(CC) $(CFLAGS) $(OBJECTS) -o $# $(LDFLAGS)
-include $(OBJECTS:.o=.d)
./client/main.cpp:
#include "bar.h"
int main()
{
Bar b;
b.sayHello();
b.sayBye();
return 0;
}
./client/bar.h
#ifndef __BAR__
#define __BAR__
#include <test_lib/foo.h>
#include <iostream>
struct Bar : public Foo
{
Bar() {};
~Bar() {};
void sayBye() const {
std::cout << "Bye " << name << "..." << std::endl;
};
};
#endif
./lib/test_lib/include/foo.h
#ifndef __FOO__
#define __FOO__
struct Foo
{
const char *name;
Foo(const char *name = "world");
~Foo();
void sayHello() const;
};
#endif
./lib/test_lib/src
#include "foo.h"
#include <iostream>
Foo::Foo(const char *name) : name(name) {}
Foo::~Foo() {}
void Foo::sayHello() const
{
std::cout << "Hello " << name << " !" << std::endl;
}
Problem was that I copied the library headers all the time in /usr/local so the files got newer and the client make then thought every header of the library had changed.
A simple fix to this problem was to replace in the library Makefile the following line:
sudo rm -rf /usr/local/include/test_lib && sudo cp -r $(INC_FOLDER) /usr/local/include/test_lib
by
sudo rm -rf /usr/local/include/test_lib && sudo ln -s $(CUR_DIR)/$(INC_FOLDER) /usr/local/include/test_lib
On a side note, provided example is missing the removal of .d files on the clean rule.
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.
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.