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.
Related
I have this Makefile:
CFLAGS = -ffreestanding -O2 -nostdlib -lgcc
BUILD_DIR = ../build
BIN = $(BUILD_DIR)/os.bin
LINKER_SCRIPT = linker.ld
OBJ_FILES := $(shell find $(BUILD_DIR) -iname '*.o')
.PHONY: all
all:
#make -C boot
#make -C kernel
$(CC) -T $(LINKER_SCRIPT) -o $(BIN) $(CFLAGS) $(OBJ_FILES)
After compiling (doing make in boot and kernel directories) there should be files with .o extension, however OBJ_FILES is empty. Only after calling make again OBJ_FILES contains the .o files paths which are needed to link. So my question is how do I update OBJ_FILES after compiling in the boot and kernel directories, because OBJ_FILES doesn't update/refresh.
Let's say you have following structure:
.
|-- Makefile
|-- boot
| |-- Makefile
| |-- boot.c
| `-- boot.h
|-- kernel
| |-- Makefile
| |-- kernel.c
| `-- kernel.h
`-- main.c
and your Makefile looks like this
location = $(CURDIR)
OBJ_FILES = $(shell find $(location) -name '*.o')
all: make_common
gcc -o main main.c $(OBJ_FILES)
make_common:
#make -C boot
#make -C kernel
clean:
-rm boot/boot.o
-rm kernel/kernel.o
Your source code is quite simple:
> cat boot/boot.h
int boot();
> cat boot/boot.c
int boot() {
return 1;
}
> cat kernel/kernel.h
int kernel();
> cat kernel/kernel.c
int kernel() {
return 2;
}
> cat main.c
#include "boot/boot.h"
#include "kernel/kernel.h"
int main() {
int result = boot() + kernel();
return 0;
}
"inner" Makefiles contain
> cat boot/Makefile
all:
gcc -c boot.c
> cat kernel/Makefile
all:
gcc -c kernel.c
you will get what you are looking for
> make clean
rm boot/boot.o
rm: boot/boot.o: No such file or directory
make: [clean] Error 1 (ignored)
rm kernel/kernel.o
rm: kernel/kernel.o: No such file or directory
make: [clean] Error 1 (ignored)
> make
gcc -c boot.c
gcc -c kernel.c
gcc -o main main.c ..../boot/boot.o ..../kernel/kernel.o
VAR = val
Expanded when the variable is used.
So my question is how do I update OBJ_FILES after compiling in the boot and kernel directories, because OBJ_FILES doesn't update/refresh.
OBJ_FILES variable won't change its value once make started executing the rules.
See 3.7 How make Reads a Makefile for full details:
GNU make does its work in two distinct phases. During the first phase it reads all the makefiles, included makefiles, etc. and internalizes all the variables and their values and implicit and explicit rules, and builds a dependency graph of all the targets and their prerequisites. During the second phase, make uses this internalized data to determine which targets need to be updated and run the recipes necessary to update them.
It’s important to understand this two-phase approach because it has a direct impact on how variable and function expansion happens; this is often a source of some confusion when writing makefiles.
What you can do instead is restart make once it built kernel and boot:
all: $(BIN)
$(BIN) : $(OBJ_FILES)
$(CC) -T $(LINKER_SCRIPT) -o $# $(CFLAGS) $(OBJ_FILES)
Makefile :
#$(MAKE) -C boot
#$(MAKE) -C kernel
touch $# # <---- Causes the Makefile to be re-read.
.PHONY: all
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
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.
When I do practice , I have a practice path.
Under this path , I have an Include path named myInclude (I have some useful function is this folder and I always use it.)
And a code path named symbol_try.I always make add new folder (with a c file and main function in it) in symbol_try and compile it.
Each time I have to compile it by gcc in terminal .Its a boring work , so I write a Makefile.
Here is an example:
the main Makefile in practice path:
FOBJS=
include myInclude/Rule.mk
include symbol_try/codeList_13.1/Rule.mk
symbol:$(FOBJS) <==What exactly I what . A executable file.
gcc -o symbol $(FOBJS) -pthread -lpthread
subsystem:
cd myInclude/ && $(MAKE)
cd symbol_try/codeList_13.1/ &&$(MAKE)
clean:
rm -rf symbol
In the myInclude/Rule.mk
FOBJS+=myInclude/otherFunction.o myInclude/error.o \
myInclude/unit.o myInclude/unitTest.o\
In the symbol_try/codeList_13.1/Rule.mk
FOBJS+=symbol_try/codeList_13.1/codeList_13.1.o
In myInclude/Makefile:
OBJS=otherFunction.o error.o unit.o unitTest.o
ALL:$(OBJS)
.PHONY:ALL
$(OBJS):%.o:%.c
gcc -c $< -o $#
clean :
otherFunction.o error.o unit.o
In symbol_try/codeList_13.1/Makefile:
codeList_13.1.o:codeList_13.1.c
gcc -c codeList_13.1.c
Well.That can work. But as you see , I have to write a Rule.mk(to initialize the FOBJS) and a Makefile for each folder.
I am new for make , I want find a way more concise , witch I only need write one Makefile for each folder and a main Makefile.No Rule.mk any more.
PS: I always change the code in myInclude ,so I don't want to build it a library.
Thanks for any help.
Here's one way you can do it with just one Makefile:
CC = gcc
CPPFLAGS += -I myInclude/ (1)
CFLAGS += -std=c99 -Wall (2)
VPATH = myInclude/ \ (3)
symbol_try/codeList_13.1/
symbol: otherFunction.o error.o unit.o unitTest.o codeList_13.1.o (4)
$(CC) -o $# $^ (5)
.PHONY : clean
clean:
rm -f symbol *.o
Note that make knows how to build C files and has some standard macros: CC, CPPFLGAS, CFLAGS
Add the include paths of your headers. You presumably have some headers for the individual object files in the myInclude directory.
Put the compiler flags here.
Add the paths to the source files you want to build.
List the object files that the executable depends upon
As there is no file called symbol.c you need to tell make how to create symbol.o with a rule. $# means the target ('symbol', here), and $^ means all of the prerequisites (the object files listed).
Here's a list of all of the files in my test directories for this:
$ find . -type f
.
./Makefile
./myInclude/error.c
./myInclude/header.h
./myInclude/otherFunction.c
./myInclude/unit.c
./myInclude/unitTest.c
./symbol_try/codeList_13.1/codeList_13.1.c
And the build output:
$ make
gcc -std=c99 -Wall -I myInclude/ -c -o otherFunction.o myInclude/otherFunction.c
gcc -std=c99 -Wall -I myInclude/ -c -o error.o myInclude/error.c
gcc -std=c99 -Wall -I myInclude/ -c -o unit.o myInclude/unit.c
gcc -std=c99 -Wall -I myInclude/ -c -o unitTest.o myInclude/unitTest.c
gcc -std=c99 -Wall -I myInclude/ -c -o codeList_13.1.o symbol_try/codeList_13.1/codeList_13.1.c
gcc -o symbol otherFunction.o error.o unit.o unitTest.o codeList_13.1.o
Why don't you create a library from the objects in myInclude and do the linking in the Makefile in your code path (symbol_try/codeList_13.1). The latter is better anyway because the needed libraries (-pthread -lpthread in your case) might change as well for some other code.
The main Makefile now would have got nothing to do but call make in all needed subdirectories.
In each folder have a makefile with
SOURCES=sample.c sampletest.c
OBJECTS=$(SOURCES:%.c=$(OBJDIR)/%.o)
all: $(OBJECTS)
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) -o $# $<
In the root directory of a project, create a makefile with a rule to compile every sub-folder like the below.
Dirs= path-to-rootdir
objs:
set -e ; \
for i in $(Dirs) ; do \
$(MAKE) CC="$(CC)" CFLAGS="$(CFLAGS_MODULE)" LDFLAGS="$(LDFLAGS)" OBJDIR="$(OBJDIR)" -C $$i; \
done
And then you could use it build the executable by adding a rule
EXE: objs
$(CC) -L./Path1 $(LIB_PATH) -llib1 -o $(EXE_NAME) $(wildcard $(OBJDIR)/*.o)
Hope this helps!!!
I want to make a make file for my lexical analyzer using flex ,I have tried to many templates of make files but it did not work so please help me build one here is the lines to compile the code:
lex -t lexical.l > lexical.c
cc -c -o lexical.o lexical.c
cc -o lexy lexical.o -ll
If you're using GNU make you don't need a makefile at all. Built-in rules cover your use case.
Let's print built-in rules and see whether make knows how to transform '%.l' to '%.c'.
$ make -p | grep -A6 '\.l\.c'
make: *** No targets specified and no makefile found. Stop.
.l.c:
# Implicit rule search has not been done.
# Modification time never checked.
# File has not been updated.
# recipe to execute (built-in):
#$(RM) $#
$(LEX.l) $< > $#
It does. In a similar way you can check that GNU make knows how to build '%.o' from '%.c' and a '%' executable from '%.o'.
Assuming that there's a lexical.l in the current directory and there's no makefile let's see how would make build lexical.
$ make -n lexical
rm -f lexical.c
lex -t lexical.l > lexical.c
cc -c -o lexical.o lexical.c
cc lexical.o -o lexical
rm lexical.c lexical.o
Great. All we miss is the -ll flag for linking you asked for. Let's add it to LDLIBS.
$ make -n lexical LDLIBS=-ll
rm -f lexical.c
lex -t lexical.l > lexical.c
cc -c -o lexical.o lexical.c
cc lexical.o -ll -o lexical
rm lexical.c lexical.o
Voilà! As a result your makefile can be as short as
LDLIBS=-ll
all: lexical
A starting point would be
LEX = lex
.l.c:
$(LEX) -t $< >$#
.c.o:
$(CC) -o $# -c $<
lexy: lexical.o
$(CC) -o $# $^ -ll
This needs to be extended with clean rules, dependency tracking and so on, but I think you should be able to get the idea how Makefiles work.
GNU make has already defined the necessary rules for this. Just put this in a file named Makefile
LDLIBS = -ll
lexy: lexical.o
lexical.o: lexical.l
and run
$ make
and you're done.