Generic Makefile with subdirectories - c

SOLVED
I had no *.h file for the target which made it fail to use my rule.
I'm trying to write a Makefile for a C project with the following project structure, but I can't really understand why my current Makefile isn't working.
project
|-src
| |-tests
So I want to compile my tests and run them in src/tests. My current Makefile looks like this.
0 CC=gcc
1 FLAGS=-std=gnu11 -Wall -Werror -lcunit
2
3 DIR_SRC=src
4 DIR_DIST=dist
5 DIR_TEST=src/tests
6
7 SRC = $(wildcard $(DIR_SRC)/*.c)
8 TAR = $(SRC:.c=.o)
9 SRC_TEST = $(wildcard $(DIR_TEST)/*.c)
10 TAR_TEST = $(SRC_TEST:.c=.o)
11
12 all: $(TAR)
13
14 tests_all: $(TAR_TEST)
15
16 tests_clean:
17 rm -f $(TAR_TEST)
18
19 $(DIR_TEST)/%.o: $(DIR_TEST)/%.c $(DIR_TEST)/%.h
20 $(CC) -c $(FLAGS) $< -o $#
But when I run make tests_all I get this:
gcc -c -o src/tests/test_tree.o src/tests/test_tree.c
which I'm guessing is a default rule, because if I remove my rule that's on row 19-20, the same thing is outputted.
I can't make sense of this, does anyone have a clue why it's not working?

Related

Can't the gcc linker just find my other files?

So here's something I don't understand : Every single time you include something in c, you have to do #include "dir/subdir/file.h". Since the .c file is in the exact same place, why do I also have to do gcc main.c dir/subdir/file.c -o main ?
It doesn't seem to make sense, every single other language I've used (arguably not that many, but still, several) was able to make sense of imports on its own. Am I missing something ? Is there a way to tell gcc to "just find them yourself" ?
gcc main.c dir/subdir/file.c -o main is not the typical command form for most projects. It is used only for simple projects, such as student assignments.
Much commercial code consists of dozens, hundreds, or thousands of source files. It is not compiled all at once. Build tools such as make or Xcode are used to manage the project, and they will compile each source file separately to its own object file.
Object files may be grouped by subproject, may be collected into libraries, and may be further processed before being linked into an executable file or other product.
When the project is built, there is no need to compile all of the source files because they have been compiled previously. It is only necessary to compile source files for object files that may change due to source edits that have been made since the last time the project was built. Thus, the build tool may compile only a few of the hundreds of source files in the project, using an individual compile command for each. Having a single command that compiled all of the source files would be wasteful.
In some projects, there may be several variants of the source file for one header file. One header file may declare common interfaces, but several different source files may provide different implementations for those interfaces, to target different types of destination systems or to provide different characteristics, such as prioritizing speed over memory or vice-versa. In such a situation, knowing the header file does not identify which source file is to be compiled.
If you want your project to compile all source files that are implied by header files, you can write your own program that scans the main.c file to find included header files (possibly recursively) and generate commands to compile the associated source files.
C is a product of early 1970s, and this is one of the areas where that really shows. An #include statement simply loads the contents of the specified file before it gets compiled - the path of the included file isn't being analyzed or preserved anywhere. Similarly, gcc isn't preserving the path of any of the files on the command line - it just loads the source from the specified file, translates it, and spits out an object file at the end.
C doesn't specify any kind of package management semantics. Each file on the gcc command line is compiled separately, and gcc doesn't know anything about the environment other than what's specified on the command line.
Yes, you could build a compiler that does all that analysis and tries to be smart about paths and such, but it's a crapload of work, there's no specification for it, no two compilers would do it the same way, and it kind of violates the spirit of C (the programmer is assumed to always know what they're doing, even when they don't).
Having said all that...
With gcc, you can use the -I option to specify additional include paths:
gcc -o main -I /dir/subdir main.c /dir/subdir/file.c
so in your source you don't need to use an explicit path in the #include:
#include "file.h" // no need for /dir/subdir path
Similarly, you can use -L to specify additional directories to search for libraries (linked with -l):
gcc -o main -I /dir/subdir main.c /dir/subdir/file.c -L /anotherdir/subdir/libs -lmylib.a
Like Eric says, if you're having to manage source across multiple directories, you should be using make or a similar tool - doing all this manually on the command line rapidly gets unscalable.
EDIT
I think an example may be helpful. I have a simple C program made up of three files - main.c, foo.c, and bar.c:
/**
* main.c
*/
#include <stdio.h>
/**
* Notice no explicit path on either include
*/
#include "foo.h"
#include "bar.h"
int main( void )
{
printf( "calling foo: " );
foo();
printf( "calling bar: " );
bar();
return 0;
}
/**
* foo.c
*/
#include <stdio.h>
#include "foo.h"
void foo( void )
{
puts( "In function foo" );
}
/**
* bar.c
*/
#include <stdio.h>
#include "bar.h"
void bar( void )
{
puts( "In function bar" );
}
Because I'm insane, I've split the source code up over multiple directories like so:
make_example/
Makefile
build/
include/
package/
src/
main.c
subdir.mk
Makefile
subdir1/
Makefile
foo.c
foo.h
subdir2/
Makefile
bar.c
bar.h
I want to do the following:
Build foo.c and bar.c and write their object files to make_example/build;
Copy foo.h and bar.h to make_example/include;
Build main.c, which includes the headers for foo and bar from make_example/includes, and write its object file to make_example/build;
Build an executable named demo from main.o, foo.o, and bar.o and save it to the make_example/package directory.
IOW, after my build is done, I want the following:
make_example/
Makefile
build/
bar.o
foo.o
main.o
include/
bar.h
foo.h
package/
demo
src/
main.c
subdir.mk
Makefile
subdir1/
Makefile
foo.c
foo.h
subdir2/
Makefile
bar.c
bar.h
I have a Makefile at the top level directory and each of my source directories. Here's the top-level Makefile (make_example/Makefile):
CC=gcc
CFLAGS=-std=c11 -pedantic -Wall -Werror
TARGET=package/demo
SUBDIRS=src
all: $(TARGET)
#
# Makes sure we build all source subdirectories before
# attempting to build the target
#
$(TARGET) : $(SUBDIRS)
$(CC) -o $# $(CFLAGS) $(wildcard build/*.o)
#
# Executes the Makefile in each source subdirectory
# with the current goal (all or clean)
#
$(SUBDIRS):
$(MAKE) -C $# $(MAKECMDGOALS)
clean: $(SUBDIRS)
rm -rf $(TARGET)
.PHONY: $(SUBDIRS) all clean
Here's the Makefile for the top-level source directory (make_example/src/Makefile):
CC=gcc
CFLAGS=-std=c11 -pedantic -Wall -Werror -g
TOPDIR=..
BLDDIR=$(TOPDIR)/build
INCDIR=$(TOPDIR)/include
#
# Look for foo.h and bar.h in the ../include
# subdirectory.
#
CFLAGS += -I $(INCDIR)
SUBDIRS=$(wildcard subdir*/.)
SRCS=main.c
OBJS=$(SRCS:%.c=$(BLDDIR)/%.o)
TARGET=main
#
# Required for the $(OBJS) target - expands
# all of the $$ expressions
#
.SECONDEXPANSION:
all: $(TARGET)
#
# Makes sure the subdirectories are
# built before attempting to build our
# target
#
$(TARGET) : $(SUBDIRS) $(OBJS)
#
# Executes the Makefile in each of the source
# subdirectories with the current goal (all or clean)
#
$(SUBDIRS):
$(MAKE) -C $# $(MAKECMDGOALS)
$(OBJS): $$(patsubst $(BLDDIR)/%.o, %.c, $$#)
$(CC) -c -o $# $(CFLAGS) $<
clean: $(SUBDIRS)
rm -rf $(OBJS)
.PHONY: all $(TARGET) $(SUBDIRS)
Since the Makefile for each of subdir1 and subdir2 is identical except for the file names, I created the subdir.mk file for the stuff that's common between the two:
CC=gcc
CFLAGS=-std=c11 -pedantic -Wall -Werror -g
TOPDIR=../..
BLDDIR=$(TOPDIR)/build
INCDIR=$(TOPDIR)/include
OBJS=$(SRCS:%.c=$(BLDDIR)/%.o)
HDRS=$(SRCS:%.c=$(INCDIR)/%.h)
all: $(OBJS) $(HDRS)
clean:
rm -rf $(OBJS) $(HDRS)
#
# Required for the $(OBJS) and $(HDRS) targets - expands
# all of the $$ expressions
#
.SECONDEXPANSION:
$(OBJS) : $$(patsubst $(BLDDIR)/%.o,%.c,$$#)
$(CC) -c -o $# $(CFLAGS) $<
#
# Copy the header files to the ../../include
# directory
#
$(HDRS) : $$(patsubst $(INCDIR)/%.h,%.h,$$#)
cp $< $#
.PHONY: all clean
Then each of the make_example/src/subdir* Makefiles is
SRCS=foo.c
include ../subdir.mk
and
SRCS=bar.c
include ../subdir.mk
So, at the top level (make_example), we simply type
make
which gives us
$ make
make -C src
make[1]: Entering directory '/home/john/Development/make_example/src'
make -C subdir2/.
make[2]: Entering directory '/home/john/Development/make_example/src/subdir2'
gcc -c -o ../../build/bar.o -std=c11 -pedantic -Wall -Werror -g bar.c
cp bar.h ../../include/bar.h
make[2]: Leaving directory '/home/john/Development/make_example/src/subdir2'
make -C subdir1/.
make[2]: Entering directory '/home/john/Development/make_example/src/subdir1'
gcc -c -o ../../build/foo.o -std=c11 -pedantic -Wall -Werror -g foo.c
cp foo.h ../../include/foo.h
make[2]: Leaving directory '/home/john/Development/make_example/src/subdir1'
gcc -c -o ../build/main.o -std=c11 -pedantic -Wall -Werror -g -I ../include main.c
make[1]: Leaving directory '/home/john/Development/make_example/src'
gcc -o package/demo -std=c11 -pedantic -Wall -Werror build/foo.o build/main.o build/bar.o
And now we have all our build artifacts where we want them:
$ ls -l */*
-rw-rw-r-- 1 john john 5744 Oct 23 16:13 build/bar.o
-rw-rw-r-- 1 john john 5744 Oct 23 16:13 build/foo.o
-rw-rw-r-- 1 john john 5984 Oct 23 16:13 build/main.o
-rw-rw-r-- 1 john john 56 Oct 23 16:13 include/bar.h
-rw-rw-r-- 1 john john 56 Oct 23 16:13 include/foo.h
-rwxrwxr-x 1 john john 21752 Oct 23 16:13 package/demo
-rw-rw-r-- 1 john john 165 Oct 23 12:54 src/main.c
-rw-rw-r-- 1 john john 555 Oct 23 15:50 src/Makefile
-rw-rw-r-- 1 john john 481 Oct 23 15:46 src/subdir.mk
src/subdir1:
total 12
-rw-rw-r-- 1 john john 89 Oct 23 12:29 foo.c
-rw-rw-r-- 1 john john 56 Oct 23 12:07 foo.h
-rw-rw-r-- 1 john john 32 Oct 23 15:16 Makefile
src/subdir2:
total 12
-rw-rw-r-- 1 john john 89 Oct 23 15:03 bar.c
-rw-rw-r-- 1 john john 56 Oct 23 14:49 bar.h
-rw-rw-r-- 1 john john 32 Oct 23 15:17 Makefile
And our program runs as
$ ./package/demo
calling foo: In function foo
calling bar: In function bar
To clean up, all I have to do is type make clean:
$ make clean
make -C src clean
make[1]: Entering directory '/home/john/Development/make_example/src'
make -C subdir2/. clean
make[2]: Entering directory '/home/john/Development/make_example/src/subdir2'
rm -rf ../../build/bar.o ../../include/bar.h
make[2]: Leaving directory '/home/john/Development/make_example/src/subdir2'
make -C subdir1/. clean
make[2]: Entering directory '/home/john/Development/make_example/src/subdir1'
rm -rf ../../build/foo.o ../../include/foo.h
make[2]: Leaving directory '/home/john/Development/make_example/src/subdir1'
rm -rf ../build/main.o
make[1]: Leaving directory '/home/john/Development/make_example/src'
rm -rf package/demo
and all our build artifacts are gone:
$ ls -l */*
-rw-rw-r-- 1 john john 165 Oct 23 12:54 src/main.c
-rw-rw-r-- 1 john john 555 Oct 23 15:50 src/Makefile
-rw-rw-r-- 1 john john 481 Oct 23 15:46 src/subdir.mk
src/subdir1:
total 12
-rw-rw-r-- 1 john john 89 Oct 23 12:29 foo.c
-rw-rw-r-- 1 john john 56 Oct 23 12:07 foo.h
-rw-rw-r-- 1 john john 32 Oct 23 15:16 Makefile
src/subdir2:
total 12
-rw-rw-r-- 1 john john 89 Oct 23 15:03 bar.c
-rw-rw-r-- 1 john john 56 Oct 23 14:49 bar.h
-rw-rw-r-- 1 john john 32 Oct 23 15:17 Makefile

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

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 $# $^

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.

C Makefile - subdirectories for different file endings

I'm currently trying to work out a Makefile that I could use for multiple projects without the need to change it for every single project. However I recently began programming in C and making Makefiles
This is my current project structure.
project
| src
| gd.c, gd.h, geom.c(only file with main function)
| obj // *.o files should be created here
| bin // executable should be created here
| Makefile
This is what I have build so far, but am not sure at all how to specify the subdirectories for the compiled/linked files.
1 TARGET = projectname
2 LIBS = -lm
3 CC = gcc
4 CFLAGS = -std=c11 -Wall
5 LD = gcc
6 LDFLAGS = -Wall
7
8 SRCDIR = src
9 OBJDIR = obj
10 EXEDIR = bin
11
12 SOURCES =
13 HEADERS =
14 OBJECTS =
15
16 $(EXEDIR)/$(TARGET): $(OBJECTS)
17 $(LD) $(OBJECTS) $(LDFLAGS) -o $# $(LIBS)
18
19 $(OBJECTS): $(SOURCES) $(HEADERS)
20 $(CC) $(CFLAGS) -c $< -o $#
21
22 .PHONY: clean
23 clean:
24 rm -f *.o
25
26 .PHONY: remove
27 remove: clean
28 rm -f $(EXEDIR)/$(TARGET)
My Question would be:
How can I create these files and put them in their respective subdirectory with my layout or something similar to it?
Is it possible to create the necessary folders(obj and bin) when using the make command and if so how can I do it?
If I understand well, you want to know - in your layout - how to set SOURCES, HEADERS and OBJECTS values that will make your Makefile work.
For this you can use regular expressions:
SOURCES = $(wildcard $(SRCDIR)/*.c)
OBJECTS = $(patsubst $(SRCDIR)/%.c,$(OBJDIR)/%.o,$(SOURCES))
HEADERS = $(patsubst %.c,%.h,$(SOURCES))
wildcard documentation here
patsubst documentation here
This is a simple answer, if you want to create a fully reusable Makefile you will have to deal with sources subfolders for example.
The rule to create the objects is strange (maybe it works). I think it is better if you use a rule to create one object with one source at a time, something like:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
$(CC) $(CFLAGS) -c $< -o $#
In this case the SOURCES variable become useless.
Moreover the HEADERS variable is useless I think, because in the compilation process you don't give to gcc the headers but the headers folder with gcc ... -I<headers folder>
And your clean should be rm -f $(OBJDIR)/*.o to delete the object files in the obj folder
Edit
I forgot the second question, you can use the shell commands to create the folder just before the file creation:
$(OBJDIR)/%.o: $(SRCDIR)/%.c
#mkdir $(OBJDIR)
$(CC) $(CFLAGS) -c $< -o $#

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.

Resources