Writing a makefile for modular project: Make - c

I am trying to learn makefile and below is my modular project structure:
$ pwd
/cygdrive/d/Make/Code
$ ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
.
|-Build
|-Conversion
|---bin
|-----exe
|-----obj
|---include
|---lib
|---make
|---source
|-Main
|---bin
|-----exe
|-----obj
|---include
|---lib
|---make
|---source
|-Reverse
|---bin
|-----exe
|-----obj
|---include
|---lib
|---make
|---source
Three modules are 1)Conversion 2)Reverse 3)Main. makefile for each these modules are placed in respective make folder and they prepare corresponding .o files correctly and place them in bin/obj of respective folders.
Build directory is for generating the .exe file as shown below:
$ cat makefile
all:
cd ../Conversion/make; make
cd ../Reverse/make; make
cd ../Main/make; make
Conversion:
cd ../Conversion/make; make
Reverse:
cd ../Reverse/make; make
Main:
cd ../Main/make; make
exeApp:
cd ../Main/make; make App
cConversion:
cd ../Conversion/make; make clean
cReverse:
cd ../Reverse/make; make clean
cMain:
cd ../Main/make ; make clean
cleanAll:
cd ../Conversion/make; make clean
cd ../Reverse/make; make clean
cd ../Main/make; make clean
and the makefile for main is:
#VPATH= ./../source
INCLUDES= ./../include
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
OBJLOOKDIR= ./../../Conversion/bin/obj:./../../Reverse/bin/obj:./../../Main/bin/obj
#CONBIN= ./../../Conversion/bin/obj
#REVBIN= ./../../Reverse/bin/obj
#MAINBIN= ./../../Main/bin/obj
vpath %.h $(INCLUDES)
vpath %.o $(OBJLOOKDIR)
vpath %.c ./../source
CC= gcc
CFLAGS= -Wall -c -I$(INCLUDES)
OBJECTS= driver.o
PROJECTOBJECTS= binary.o hex.o octal.o reverseNum.o driver.o
main: $(OBJECTS)
driver.o: driver.c conversion.h
$(CC) $(CFLAGS) $< -o $(OBJDIR)/$#
App: $(PROJECTOBJECTS)
$(CC) -Wall $< -o $(EXEDIR)/$#
clean:
rm -rf $(OBJDIR)/*.o *~ $(EXEDIR)/*
But when I run make exeApp, I get below error:
$ make exeApp
cd ../Main/make; make App
make[1]: Entering directory '/cygdrive/d/Make/Code/Main/make'
gcc -Wall ./../../Conversion/bin/obj/binary.o -o ./../bin/exe/App
/usr/lib/gcc/i686-pc-cygwin/4.8.2/../../../libcygwin.a(libcmain.o): In function `main':
/usr/src/debug/cygwin-1.7.28-2/winsup/cygwin/lib/libcmain.c:39: undefined reference to `WinMain#16'
collect2: error: ld returned 1 exit status
makefile:26: recipe for target 'App' failed
make[1]: *** [App] Error 1
make[1]: Leaving directory '/cygdrive/d/Make/Code/Main/make'
makefile:17: recipe for target 'exeApp' failed
make: *** [exeApp] Error 2
Some how it is not being translated to below rule:
$ pwd
/cygdrive/d/Make/Code/Main/make
Gaurav#Gaurav-PC /cygdrive/d/Make/Code/Main/make
$ gcc -Wall ./../../Conversion/bin/obj/binary.o ./../../Conversion/bin/obj/hex.o ./../../Conversion/bin/obj/octal.o ./../../Reverse/bin/obj/reverseNum.o ./../../Main/bin/obj/driver.o -o Trial
Gaurav#Gaurav-PC /cygdrive/d/Make/Code/Main/make
$ ls
makefile makefileold Trial.exe
as The above rule compiles file, but exeApp rule translated only to gcc -Wall ./../../Conversion/bin/obj/binary.o -o ./../bin/exe/App . It should have been to gcc -Wall ./../../Conversion/bin/obj/binary.o ./../../Conversion/bin/obj/hex.o ./../../Conversion/bin/obj/octal.o ./../../Reverse/bin/obj/reverseNum.o ./../../Main/bin/obj/driver.o -o ./../bin/exe/App
I am not able to figure out why?
Can anyone help, Please.
Thanks

Related

GNU make, implicit rules not needed

I have the following directory:
Makefile
src/
main.c
dummy.raw
(main.o) (<- to be built)
(dummy.txt) (<- to be built)
build/
(main) (<- to be built)
And the following Makefile:
C_FILES=$(wildcard src/*.c)
O_FILES=$(C_FILES:%.c=%.o)
main: build/main
build/main: $(O_FILES)
gcc $(O_FILES) -o build/main
src/%.o: src/%.c src/dummy.txt
echo "Compiling using my rule"
gcc -c $< -o $#
src/%.txt: src/%.raw
touch $#
#echo "Created dummy file"
clean:
rm -f src/*.o
rm -f src/*.txt
rm -f build/*
The problem is that make seems to ignore my rule for producing .o files and use its own built-in version ; in particular, it does not build dummy.txt. Here's a sample output:
$ make clean
rm -f src/*.o
rm -f src/*.txt
rm -f build/*
$ make
cc -c -o src/main.o src/main.c
gcc src/main.o -o build/main
make only starts using the rule in the Makefile if I build the .txt file myself using make src/dummy.txt.
Why is make behaving this way?
How do I correct my Makefile to force make to build the intermediate dummy.txt?
Thanks!
The trouble is that your method invokes a chain of pattern rules, one to build src/main.o and one to build src/dummy.txt, and Make will prefer an implicit rule to a chain of pattern rules.
There are a couple of ways to solve this. Two simple ones:
You could invoke Make with the ‘-r’ a.k.a. ‘--no-builtin-rules’ option:
make -r
Or you could hard-code the rule for src/dummy.txt:
src/%.txt: src/%.raw
touch $#
#echo "Created dummy file"
src/dummy.txt: src/dummy.raw

How to run and execute a makefile C

I'm trying to make a Makefile for my program. It is so difficult because i've read a lot of guide but none is clear. I have 3 files : main.c , library.c , library.h . Main.c and library.c depend on library.h . The structure of my directory project is formed by :
MyProject directory -> Build directory and Exercise1 directory -> all of my files . In compiler I wrote make and it compiled ; then when I write make execute command, it gives me this error:
cd ../build; ./test
Error: No such file or directory
makefile:23: recipe for target 'execute' failed
make: *** [execute] Error 1
MAKEFILE
CC=gcc
CFLAGS=-Wall
ODIR=../build
DIR = build
.PHONY: all
all: main.o library.o test
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -std=c99 -c -o $# $< $(CFLAGS)
library.o: library.c library.h
$(CC) -std=c99 -c -o $(ODIR)/$# $< $(CFLAGS)
main.o: main.c library.h
$(CC) -std=c99 -c -o $(ODIR)/$# $< $(CFLAGS)
test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
execute:
cd $(ODIR); ./test
clean:
rm -f $(ODIR)/*.o
These lines:
execute:
cd $(ODIR); ./test
tell make that, when you give the command make execute, it should change the working directory to $(ODIR) and then execute ./test, which means to execute the file test in the current working directory. However, there is no file test in the $(ODIR) directory because you have not built it yet.
You can make that file by executing make test, but that is a bad way to do it. It is better to tell make that the execute target depends on $(ODIR)/test:
execute: $(ODIR)/test
cd $(ODIR); ./test
Then we should change the rule for test to $(ODIR)/test:
$(ODIR)/test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
Next, delete the rule for all and the .PHONY rule. A rule for all should be used when a makefile can make several different final targets, like ProgramA, ProgramB, and ProgramC, and you want one target that makes all of them. It should not be used to make all of the intermediate object files for a target. The intermediate files should arise out of the rules for building a final target.
Then delete the rules for library.o and main.o. Those are names for files in the current directory, but you are building in $(ODIR). We will let the pattern rule for $(ODIR)/%.o build those.
But we need to fix the pattern rule. It uses DEPS, but that is not defined. Add a line above that says what all the object files depend on:
DEPS=library.h
Nothing in the makefile uses DIR, so delete the line DIR = build.
Finally, you might want to put the execute target first, so that it is the default. Then your makefile is:
CC=gcc
CFLAGS=-Wall
ODIR=../build
DEPS=library.h
execute: $(ODIR)/test
cd $(ODIR); ./test
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -std=c99 -c -o $# $< $(CFLAGS)
$(ODIR)/test: $(ODIR)/library.o $(ODIR)/main.o
$(CC) -std=c99 -o $(ODIR)/$# $^ $(CFLAGS)
clean:
rm -f $(ODIR)/*.o
You might also change the command for clean to remove test:
rm -f $(ODIR)/*.o $(ODIR)/test

rule to call another Makefile from inside a Makefile

I have a Makefile from which I run the command of another Makefile if some objects file do not exist already.
The rule is the following:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
where the variables are defined as follows in the same Makefile:
COMMONDIR := ../common
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(COMMONDIR)/obj
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
This rule works fine but at the end of the day the only real input required by the rule is the other Makefile so I tried:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
but this does not work, why is that?
For completeness here is the complete Makefile
CC = gcc
INC_PATH = -I../common/
SOURCEDIR := ./
SOURCES := $(wildcard $(SOURCEDIR)/*.c)
OBJDIR :=./obj
OBJECTS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.o, $(SOURCES))
DEPENDS := $(patsubst $(SOURCEDIR)/%.c,$(OBJDIR)/%.d, $(SOURCES))
COMMONDIR := ../common
SOURCESCOMMON := $(wildcard $(COMMONDIR)/*.c)
OBJDIRCOMMON := $(COMMONDIR)/obj
OBJECTSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.o, $(SOURCESCOMMON))
DEPENDSCOMMON := $(patsubst $(COMMONDIR)/%.c,$(OBJDIRCOMMON)/%.d, $(SOURCESCOMMON))
# ADD MORE WARNINGS!
WARNING := -Wall -Wextra
# OBJS_LOC is in current working directory,
EXECUTABLE := ../server
# .PHONY means these rules get executed even if
# files of those names exist.
.PHONY: all clean
# The first rule is the default, ie. "make",
# "make all" and "make parking" mean the same
all: $(EXECUTABLE)
clean:
$(RM) $(OBJECTS) $(DEPENDS) $(EXECUTABLE)
# Linking the executable from the object files
# $^ # "src.c src.h" (all prerequisites)
$(EXECUTABLE): $(OBJECTS) $(OBJECTSCOMMON)
$(CC) $(WARNING) $^ -o $#
-include $(DEPENDS) $(DEPENDSCOMMON)
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: $(SOURCEDIR)/%.c Makefile | $(OBJDIR)
$(CC) $(WARNING) -MMD -MP -c $(INC_PATH) $< -o $#
$(OBJDIRCOMMON):
mkdir -p $(OBJDIRCOMMON)
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
EDIT
The error I get is like this:
Entering directory '/home/user/Documents/UnixSystem/network/common'
gcc -Wall -Wextra -MMD -MP -c utilities.c -o obj/utilities.o
gcc -Wall -Wextra -MMD -MP -c error.c -o obj/error.o
make[2]: Leaving directory '/home/user/Documents/UnixSystem/network/common'
gcc ../common/obj/error.d.o -o ../common/obj/error.d
gcc: error: ../common/obj/error.d.o: No such file or directory
gcc: fatal error: no input files
compilation terminated.
From which I understand the execution of the other Makefile was successful. However after that it is trying to execute this command gcc ../common/obj/error.d.o -o ../common/obj/error.d which is wrong but I do not know which rule and why it's generating it.
Why what you did was wrong
Recipe A:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/%.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
and recipe B:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
have essentially different meanings and will certainly not yield the same behaviour.
Recipe A says:
Any target $(OBJDIRCOMMON)/file.o must be made up-to-date if does not exist
or is older than either $(COMMONDIR)/file.c or $(COMMONDIR)/Makefile.
If a target $(OBJDIRCOMMON)/file.o must be made up-to-date, then $(OBJDIRCOMMON)
must be made up-to-date first.
To make a target $(OBJDIRCOMMON)/file.o up-to-date, run the expansion of $(MAKE) -C $(COMMONDIR) in a shell.
Recipe B says:
Any target $(OBJDIRCOMMON)/file.o must be made up-to-date if does not exist
or is older than $(COMMONDIR)/Makefile.
If a target $(OBJDIRCOMMON)/file.o must be made up-to-date, then $(OBJDIRCOMMON)
must be made up-to-date first.
To make a target $(OBJDIRCOMMON)/file.o up-to-date, execute the expansion of $(MAKE) -C $(COMMONDIR) in a shell.
Notice that criterion A.1 is different from criterion B.1. Recipe A will execute
if $(OBJDIRCOMMON)/file.o is older than $(OBJDIRCOMMON)/file.c. Recipe B will not.
Recipe B discards the dependency of the object files on the corresponding source files,
and tells Make that $(OBJDIRCOMMON)/file.o is only ever to be remade if it
is older than $(COMMONDIR)/Makefile.
at the end of the day the only real input required by the rule is the other Makefile
What you mean by "the rule" here is actually the commandline (expanded from) $(MAKE) -C $(COMMONDIR).
The inputs of this command are one thing; the criteria for executing it are another.
How what you did caused the error you see.
This is thornier. Let's reproduce it.
Here's a playpen:
$ ls -R
.:
app common
./app:
foo.c main.c Makefile
./common:
bar.c Makefile
Here, ./app/Makefile is exactly your Makefile with recipe A. ./common/Makefile,
which you didn't post, is just:
obj/bar.o: bar.c
gcc -MMD -MP -c -I. $< -o $#
because that will do for illustration.
We build in ./app:
$ cd app
$ make
mkdir -p ./obj
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
mkdir -p ../common/obj
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
which is fine.
Now I change ./app/Makefile as you did, to use recipe B, and rebuild.
$ make
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
Still fine... But wait a minute! That one didn't invoke the ./common make
at all, which is the one that the change might affect. Better clean:
$ make clean
rm -f ./obj/foo.o ./obj/main.o ./obj/foo.d ./obj/main.d ../server
and try again:
$ make
gcc -Wall -Wextra -MMD -MP -c -I../common/ foo.c -o obj/foo.o
gcc -Wall -Wextra -MMD -MP -c -I../common/ main.c -o obj/main.o
gcc -Wall -Wextra obj/foo.o obj/main.o ../common/obj/bar.o -o ../server
No difference? Ah, that's because this Makefile's clean fails to delete all
the files that make builds: it leaves out ../common/obj/bar.o. So I'll just:
$ rm ../common/obj/*
And have another go:
$ make
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
gcc: error: ../common/obj/bar.d.o: No such file or directory
gcc: fatal error: no input files
compilation terminated.
which is your mystery.
When I zapped the ../common/obj files, I deleted not only all the object files therein
but also the dependency file ../common/obj/bar.d. And now Make is trying to remake it by running:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
How come? To answer that, we'll first change ./app/Makefile back to use recipe A
- consider it done - and then do:
$ make --print-data-base > out.txt
which dumps in out.txt all the information that Make gleans from reading all
the makefiles (Makefile and all the makefiles that it recursively include-s,
in this case just the auto-generated .d files).
Let's see what the database has to say about ../common/obj/bar.d. It says:
# Not a target:
../common/obj/bar.d:
# Implicit rule search has been done.
# Last modified 2019-01-11 16:01:33.199263608
# File has been updated.
# Successfully updated.
Certainly we don't want ../common/obj/bar.d to be a target, and it isn't a
target because, having read all the makefiles, and considered all its builtin rules,
and all of the files it can actually find, Make can't see any way in which ../common/obj/bar.d
has to be made up-to-date with respect to any of those files. Good.
Now let's revert to recipe B in ./app/Makefile again - consider it done -
and again do:
$ make --print-data-base > out.txt
and again look in out.txt concerning ../common/obj/bar.d. This time we find:
../common/obj/bar.d: ../common/obj/bar.d.o
# Implicit rule search has been done.
# Implicit/static pattern stem: '../common/obj/bar.d'
# Last modified 2019-01-11 16:01:33.199263608
# File has been updated.
# Successfully updated.
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
So this time ../common/obj/bar.d is a target! And it depends on ../common/obj/bar.d.o!
And the recipe to make it is:
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
which will expand, of course, to:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
How was Make able to work that out, thanks to recipe B?
Well first it considered whether any of the rules in the makefiles or any of the
builtin rules gave it direct way to make ../common/obj/bar.d from any existing files,
and drew a blank.
Next it considered whether any of those rules gave it a way to
make ../common/obj/bar.d from an intermediate file. An intermediate file being a file that doesn't exist but itself can be made
from existing files, by any of the rules it has read or its builtin-rules. This
time it saw a way.
One of Make's builtin pattern rules is:
%: %.o
# recipe to execute (built-in):
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
You can find it in right there in out.txt. And you can see this is the pattern rule that
it matches with:
../common/obj/bar.d: ../common/obj/bar.d.o
The recipe there is a recipe to link a program called ../common/obj/bar.d given
an object file ../common/obj/bar.d.o.
There is no object file ../common/obj/bar.d.o, but can it be an intermediate file? If
Make can find a rule for making ../common/obj/bar.d.o from files that do exist,
then it can also make ../common/obj/bar.d with this %: %.o rule.
And it can find a recipe for making ../common/obj/bar.d.o from existing files
because we just gave it one! - recipe B:
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
That tells Make that if any target matching $(OBJDIRCOMMON)/%.o (like ../common/obj/bar.d.o)
does not exist, but $(COMMONDIR)/Makefile does exist (which it does), then that target
is made up-to-date by running:
$(MAKE) -C $(COMMONDIR)
Make believed us. It ran $(MAKE) -C $(COMMONDIR):
make -C ../common
make[1]: Entering directory '/home/imk/develop/so/make_prob/common'
gcc -MMD -MP -c -I. bar.c -o obj/bar.o
make[1]: Leaving directory '/home/imk/develop/so/make_prob/common'
and then considered ../common/obj/bar.d.o up-to-date. So it moved on to:
../common/obj/bar.d: ../common/obj/bar.d.o
$(LINK.o) $^ $(LOADLIBES) $(LDLIBS) -o $#
and ran:
gcc ../common/obj/bar.d.o -o ../common/obj/bar.d
which failed because we lied:
make -C ../common
does not make ../common/obj/bar.d.o at all.
gcc: error: ../common/obj/bar.d.o: No such file or directory
This does not arise with recipe A, because
$(OBJDIRCOMMON)/bar.d.o: $(OBJDIRCOMMON)/bar.d.c $(COMMONDIR)/Makefile | $(OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR)
does not offer Make a way to make $(OBJDIRCOMMON)/bar.d.o from existing files,
because $(OBJDIRCOMMON)/bar.d.c does not exist. So ../common/obj/bar.d is not
a target.
Stick with recipe A, because it's right, and recipe B is wrong. Also review
and fix the makefiles so that make clean always deletes all the non-.PHONY targets that might have been built, and nothing else. Lastly avoid writing recipes with non-.PHONY targets where the recipe does not mention the target.
Should there be && instead of pipe
$(OBJDIRCOMMON)/%.o: $(COMMONDIR)/Makefile | (OBJDIRCOMMON)
+$(MAKE) -C $(COMMONDIR

Makefile error: /usr/bin/ld: cannot find -lsqlite3

I've installed sqlite3 from source on Linux and placed this into the subdirectory of C code with a Makefile. This is what the Makefile looks like
CC = gcc
CFLAGS = -Wall -g -std=c99
SOURCES := src/file1.c src/file2.c src/file3.c
LIB := -lm -lsqlite3
INC := -I include -I path/to/pathname/sqlite3/include
all:
#mkdir -p bin/
$(CC) $(CFLAGS) $(SOURCES) main.c -L path/to/pathname/sqlite3/ -o bin/software $(LIB) $(INC)
clean:
rm -f bin/sofware
However, whenever I try executing make, I get this error:
gcc -Wall -g -std=c99 src/file1.c src/file2.c src/file3.c -I include -I path/to/pathname/sqlite3/include
/usr/bin/ld: cannot find -lsqlite3
collect2: error: ld returned 1 exit status
make: *** [all] Error 1
I don't understand. sqlite3 is in path/to/pathname/sqlite3/
Here is the list of files/executables in path/to/pathname/sqlite3/:
aclocal.m4 config.log configure.ac install-sh ltmain.sh missing shell.o sqlite3.h sqlite3.pc.in
autom4te.cache config.status depcomp lib Makefile README sqlite3 sqlite3.lo tea
bin config.sub include libsqlite3.la Makefile.am share sqlite3.c sqlite3.o
config.guess configure INSTALL libtool Makefile.in shell.c sqlite3ext.h sqlite3.pc
How does one properly allow this C code to compile properly with access to sqlite3?
You need to add -L/path/to/lib/dir

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