Using assembly object files from a subdirectory - c

I have a small project with several .c files and one .s assembly file (crt0.s). The .c files are compiled into .o files, and are stored in the ./build subdirectory. These files compile and link correctly.
I would like the .s file to be stored in the ./build directory as well. So far, my makefile compiles the .s file and stores it in the correct location, however the linker can't find it.
The error I get is "ld.exe cannot find crt0.o". crt0.o is definitely being created in the ./build directory.
Here is the makefile:
CC=arm-none-eabi-gcc
AS=arm-none-eabi-as
CFLAGS=-nostartfiles -nodefaultlibs -fno-builtin -Wall -T linker.ld -I./Include
objects=$(addprefix $(OBJDIR)/,crt0.o main.o gpiopins.o framebuffer.o drawchar.o putchar.o intconv.o strlen.o kprintf.o kputchar.o)
OBJDIR=./build
$(OBJDIR)/%.o: %.s
$(AS) -o $# $<
$(OBJDIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
kernel.img: $(objects)
$(CC) -o kernel.img $(objects) $(CFLAGS)
.PHONY : clean
clean:
rm -f kernel.img
rm -f *.o
rm -f $(OBJDIR)/*.o
Any Ideas where I may be going wrong?
Thank you
EDIT:
If I do it manually, it is fine. eg:
kernel.img: $(objects)
arm-none-eabi-as -o crt0.o crt0.s
$(CC) -o kernel.img $(objects) $(CFLAGS)
However, this means that crt0.o is not in the ./build directory

How can the "manual" variant be ok? The var objects contains ./build/crt0.o which is what your linker needs. The as command you pushed in is not providing it, so how does it help? And even if it did, it would come too late, because all objects together are dependencies of the rule.
Do make clean and show us the output, that might help to spot what's going on.

Related

How do I get a makefile to compile multiple sources?

I would like my makefile to compile two sources, osmprun.c and echoall.c.
Currently it's just compiling osmprun.c, which creates errors.
Im at my wits end, Im not experienced with makefiles at all and I just don't understand what im doing wrong.
My makefile is:
CC=gcc
CFLAGS= -Wall -Wconversion -g
LIBS=-lm -lpthread
DEPS=
BUILD_DIR := build
SRCS := osmprun.c echoall.c
OBJS := $(addprefix $(BUILD_DIR)/,$(patsubst %.c,%.o,$(SRCS)))
$(BUILD_DIR)/%.o: %.c $(DEPS)
mkdir -p $(BUILD_DIR)
$(CC) -c $(CFLAGS) $< -o $#
echoall: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
osmprun: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
.PHONY: clean
clean:
rm -f $(BUILD_DIR)/*.o *~ core
test:
./osmprun
Can somebody help me figure out my mistake and explain what the problem is?
EDIT:
I've now changed the part where it is supposed to compile the two files to:
echoall: echoall.c
$(CC) $(CFLAGS) $^ $(LIBS) -o $#
osmprun: osmprun.c
$(CC) $(CFLAGS) $^ $(LIBS) -o $#
But it is still only compiling echoall, not osmprun
It would help greatly if you included the command you typed and the output you got, and what you wanted to get, especially because your terminology is not quite accurate. It's not true that make is not compiling all the object files. The problem is at the link stage.
However, I don't understand what your makefile is intended to do. You have two targets and they both depend on the SAME set of object files:
echoall: $(OBJS)
osmprun: $(OBJS)
Do you need to link both of those object files together? If so then what is the difference between the echoall program and the osmprun program, if they both contain the same set of object files?
Or, do you want to create the echoall program from the echoall.c source file and the osmprun program from the osmprun.c source file? If so, why do you list both objects as a prerequisite for both programs?
In any event your problem is here:
echoall: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
osmprun: $(OBJS)
mkdir -p $(BUILD_DIR)
$(CC) $(CFLAGS) $< $(LIBS) -o $#
(the mkdir here are useless: you know that the directory already exists because you already built the object files, but they don't hurt anything).
The problem is you're using $< which is the first prerequisite. Because both prerequisite lists are the same, you're building both programs from the same, single source file.
If you want both programs to contain both object files, you should use $^ here not $<. If you want each program to contain only its related object file, you should change the prerequisites to contain only the object file it should be built from (and also use $^).

Makefile cannot create a seperate Object Folder for simple project

I am using this Makefile Tutorial for understanding how to use Makefiles.
This Question might be a duplicate for this thread but I think I need more clarity here.
My Project structure:
--exercise_14/
--> ex14.c
--> ex14.h
--> main.c
--> Makefile
There is nothing complex about ex14.*, just simple header file with 3 function declarations (ex14.h) and their implementation (ex14.c) and main.c calls them.
My Makefile is as follows:
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
_OBJ=ex14.o main.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
all: ex14
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
ex14: $(OBJ)
$(CC) $(CFLAGS) -o $# $^
clean:
rm -f ex14 $(ODIR)*.o
rm -rf $(ODIR)
I am currently understanding how the patsubst in the file should work and everytime I run
make clean all
I get:
gcc -Wall -g -c -o obj/ex14.o ex14.c
Assembler messages:
Fatal error: can't create obj/ex14.o: No such file or directory
Makefile:16: recipe for target 'obj/ex14.o' failed
make: *** [obj/ex14.o] Error 1
Which makes sense that there is no obj/ folder created and no ex14.o is found for further compilation. A way around is to use mkdir obj and then perform make but I want to avoid that.
Question
What lines should be added to let my Makefile make a folder as ODIR=obj and put all the object files within it?
The correct solution is to make your object files depend on their directory via order-only dependency:
Consider an example where your targets are to be placed in a separate directory, and that directory might not exist before make is run. In this situation, you want the directory to be created before any targets are placed into it but, because the timestamps on directories change whenever a file is added, removed, or renamed, we certainly don’t want to rebuild all the targets whenever the directory’s timestamp changes. One way to manage this is with order-only prerequisites: make the directory an order-only prerequisite on all the targets:
$(ODIR)/%.o: %.c $(DEPS) | $(ODIR)
<same-original-recipe>
$(ODIR):
mkdir -p $#
As commented by others, but you can explicitly put a dependency to the $(ODIR) directory (it must be created before any dependent files ---compilation):
$(OBJS): $(ODIR)
$(ODIR):
mkdir -p $#
This will ensure you have created the $(ODIR) directory before any dependent files (any *.o file) and that it will be created only once.
The final contents of your Makefile should be as this:
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
_OBJ=ex14.o main.o
OBJ=$(patsubst %,$(ODIR)/%,$(_OBJ))
all: ex14
$(ODIR)/%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
ex14: $(OBJ)
$(CC) $(CFLAGS) -o $# $^
clean:
rm -f ex14 $(ODIR)*.o
rm -rf $(ODIR)
$(OBJ): $(ODIR)
$(ODIR):
mkdir -p $#
EDIT 2
After posting the correct rule I found some errors in the $(patsubst) variable expansion, that made make to fail when not everything was erased.
Following is a correct, optimized Makefile:
$ cat Makefile
CC = gcc
CFLAGS = -Wall -g
DEPS = ex14.h
ODIR=obj
OBJS=ex14.o main.o
POBJS=$(foreach i,$(OBJS),$(ODIR)/$(i))
LIBS= # for example: -lm for math library.
.PHONY: all ex14 clean
$(ODIR)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
all: ex14
ex14: $(POBJS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $(POBJS) $(LIBS)
clean:
rm -rf $(ODIR)
$(POBJS): $(ODIR) $(DEPS)
$(ODIR):
mkdir -p $#
putting the dependency on $(DEPS) in the
$(OBJS): $(ODIR) $(DEPS)
makes the automatic default dependency rule for .c -> .o files valid, and not needed anymore in the makefile. Also, I have used P prefix to mean pathed file in POBJS against OBJS (which is the plain list of object files) Also removing recursively the objs subdirectory makes unnecessary to remove the object files first, and then the subdirectory (only the last command is needed) Also, when linking, it is common use, to pass the compiler the $(LDFLAGS) for it to pass them to the linker. And finally, if you have some libraries to include at the end, just use a $(LIBS) library (not needed for your sample).
As stated in one of the comments, the compilation of just one source file makes the $(ODIR) directory to be touched, and all the other files to be out of date, and this will make all the files but the one just compiled to be compiled next time. There's no solution to this problem as there's a circular dependency on this (the objects depend on the directory to exist, and the directory is touched on each compilation which makes the dependency to be triggered again for all the files compiled before the last one) The only possible solution to this problem is to eliminate the dependency on the directory and construct it by hand before calling make.
Berkeley make (pmake or bmake, it depends) has a workaround to this problem, by allowing you to define a .BEGIN dependency, that is to be solved before any other work. You can create the directory there. I think GNU make doesn't have this feature:
.BEGIN:
mkdir -p $(ODIR)
But this is out of scope for this question that is directed to GNU make.

MakeFile: error: <jni.h>: No such file or directory

I am trying to call java from c, and I have made the following MakeFile:
include ../../Makefile.defs
auto_gen=
NAME=libproto.so
CC=gcc
CFLAGS= -g -Wall -fPIC
LIBS= -L'$(LD_LIBRARY_PATH)' -ljvm -I"/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.91.x86_64/include/" -I"/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.91.x86_64/include/linux" -I"/usr/local/lib64/kamailio/"
include ../../Makefile.modules
SOURCE=jni_wrapper.c ProtoType.c
OBJECTS=$(SOURCE:.c=.o)
all: $(SOURCE) $(NAME)
%.o: %.c
$(CC) $(CFLAGS) -c $(LIBS) $<
clean:
rm -f $(EXEC); rm -f *~; rm -f .*.swp; rm -f .*.swo; rm -f *.o
java:
javac ProtoType.java
jar cf ProtoType.jar ProtoType.class
javap -s -p ProtoType > sigs.txt
cat sigs.txt
When I compile with make I get an error like this:
error: <jni.h>: No such file or directory
I looked through many stackoverflow pages with a similar problem but they all have same solution which I already had implemented. They said you need to link the library path to jni.h.
As you can see in my MakeFile this is being done:
LIBS= -L'$(LD_LIBRARY_PATH)' -ljvm -I"/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.91.x86_64/include/" -I"/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.91.x86_64/include/linux" -I"/usr/local/lib64/kamailio/"
I triple checked the directories and the permissions and everything is fine.
Any Suggestions?
You need to add the end of your LIBS definition to the CFLAGS
CFLAGS= -g -Wall -fPIC -I"/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.91.x86_64/include/" -I"/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.91.x86_64/include/linux" -I"/usr/local/lib64/kamailio/"
LIBS= -L'$(LD_LIBRARY_PATH)' -ljvm
The -I include directories are used by the compiler not the linker. It's the compiler that can't find your .h file.
You may also want to change the targets as follows
%.o: %.c
$(CC) $(CFLAGS) -c $<
$(NAME): $(OBJECTS)
$(CC) $(OBJECTS) -o $# $(LIBS)
This will build you .so file.

Including a .h file and directing .o files to a directory: Make

I am trying to learn make files.
My directory Structure is
$ ls -R | grep ":$" | sed -e 's/:$//' -e 's/[^-][^\/]*\//--/g' -e 's/^/ /' -e 's/-/|/'
.
|-bin
|---exe
|---obj
|-build
|-include
|-lib
|-make
|-source
What I am trying to do is place my include file conversion.h in include folder, all .c files in source, makefile in make, compiled all .o files in bin/obj and exe in /bin/exe
I referred below posts:
makefile include *.h file in other directory
Using make to move .o files to a separate directory
my makefile is:
VPATH= ./../source
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
#vpath %.o $(OBJDIR)
CFLAGS= -Wall -c -I.
#INCLUDES= -I./../include
objects= binary.o hex.o octal.o
conversion: $(objects)
# gcc -Wall -o conversion $(objects) -I.
binary.o: binary.c conversion.h
gcc $(CFLAGS) $< -o $(OBJDIR)/$#
octal.o: octal.c conversion.h
gcc $(CFLAGS) $< -o $(OBJDIR)/$#
hex.o: hex.c conversion.h
gcc $(CFLAGS) $< -o $(OBJDIR)/$#
clean:
rm -rf $(OBJDIR)/*.o *.o *~ conversion
I am using cygwin.
My questions are:
1) I am not able to include my conversion.h from location ./../include
,-I. works fine if I copy conversion.h to make folder
-but as soon as I replace with -I./../include without any copy of conversion.h in make folder
I get below error
$ make
make: *** No rule to make target 'conversion.h', needed by 'binary.o'. Stop.
2) My makefile does place all .o files to /bin/obj but when I try to use vpath as shown below (instead of using manual placement like --o $(OBJDIR)/$#)
vpath %.o $(OBJDIR)
...
$(OBJDIR)/binary.o: binary.c conversion.h
gcc $(CFLAGS) $< -o $#
...
...
doing above replacement for all .o rules,does not place all .o files to bin/obj directory
Any help would be appreciated.
Thanks
You have to be explicit about the locations of the .h file, the .c files, the .o files, and the executable when you define the targets and their dependencies.
VPATH= ./../source
INCLUDEDIR= ./../include
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
#vpath %.o $(OBJDIR)
INCLUDES= -I./../include
CFLAGS= -Wall -c -I. $(INCLUDES)
objects= $(OBJDIR)/binary.o $(OBJDIR)/hex.o $(OBJDIR)/octal.o
$(EXEDIR)/conversion: $(objects)
# gcc -Wall -o conversion $(objects) -I.
$(OBJDIR)/binary.o: $(VPATH)/binary.c $(INCLUDEDIR)/conversion.h
gcc $(CFLAGS) $< -o $#
$(OBJDIR)/octal.o: $(VPATH)/octal.c $(INCLUDEDIR)/conversion.h
gcc $(CFLAGS) $< -o $#
$(OBJDIR)/hex.o: $(VPATH)/hex.c $(INCLUDEDIR)/conversion.h
gcc $(CFLAGS) $< -o $#
clean:
rm -rf $(OBJDIR)/*.o *.o *~ $(EXEDIR)/conversion
Since your header files are in a separate directory, make cannot locate them. Since it can't locate them, it tries to build them by looking for a target rule. Since it cant find a target, you get the error listed in your question.
The -I./../includes only affects the compiler's include search path. It does not affect how make looks for include.
If you want make to search for your header files you will need to add a vpath for the headers. You will likely get the same error for the source files since they are in a separate directory as well. Thus, you will need to add a vpath for the source files as well.
To get your original to work with vpath as opposed to explicit locations, try the following:
VPATH= ./../source
OBJDIR= ./../bin/obj
EXEDIR= ./../bin/exe
INCLUDES= -I./../include
vpath %.c $(VPATH)
vpath %.h $(INCLUDES)
vpath %.o $(OBJDIR)
CFLAGS= -Wall -c -I. $(INCLUDES)
As noted in my comment and the comments for your referenced question, it is not recommended to use vpath to locate object files.

make file, Is this look ok?

all: run
run: test.o list.o matrix.o smatrix.o
gcc test.o list.o matrix.o smatrix.o -o matrix-mul
list.o: list.c list.h
gcc -g -c list.c
matrix.o: matrix.c matrix.h
gcc -g -std=c99 -c -o matrix.o matrix.c
smatrix.o: smatrix.c smatrix.h
gcc -g -c -o smatrix.o smatrix.c
test.o: test.c test.h
gcc -g -c test.c
I was having lots of problems to make a makefile and I finally got this working. And I just want to make sure these are ok (not just for making program running but in term of a good make file)
One question is that why do matrix.o and smatrix.o have .o files in the line gcc -g -c ... where as list.o and test.o don't have that line..
I had to add -std=c99 because I was getting some weird for loop error but still don't understand why I need to put matrix.o in the line..
The file is OK-ish. It is not very easily maintainable.
This website has a really good tutorial on how to make nice makefiles:
http://mrbook.org/blog/tutorials/make/
Especially look at the last example:
CC=g++
CFLAGS=-c -Wall
LDFLAGS=
SOURCES=main.cpp hello.cpp factorial.cpp
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=hello
all: $(SOURCES) $(EXECUTABLE)
$(EXECUTABLE): $(OBJECTS)
$(CC) $(LDFLAGS) $(OBJECTS) -o $#
.cpp.o:
$(CC) $(CFLAGS) $< -o $#
This should show you how to enhance maintainability (add extra files to SOURCES, and the rest is done automatically.
The below file supports make all make depend and make clean - you only need to change the first lines. Remember to make depend if you change includes in any file.
TARGET:=matrix-mul
SOURCES:=test.c list.c matrix.c smatrix.c
OBJECTS:=$(SOURCES:%.c=%.o)
CC=gcc
CFLAGS=-g -std=c99 -Wall
LD=gcc
LDFLAGS=
# First target - simply say that we want to produce matrix-mul
all: $(TARGET)
# To create the target we need all .o files, and we link with LD/LDFLAGS
# $# is the file we're making, aka matrix-mul
$(TARGET): $(OBJECTS)
$(LD) -o $# $(OBJECTS) $(LDFLAGS)
#Creating a .o from a .c
# $< is the c file, $# is the corresponding .o file
.c.o:
$(CC) $(CFLAGS) -c $< -o $#
# Regenerate dependencies
depend:
$(CC) $(CFLAGS) -MM $(SOURCES) > .depend
# Remove produced files
clean:
rm -rf $(OBJECTS) $(TARGET) .depend
# If there's no dependency file, create it
.depend: depend
# Include the autogenerated dependency file
include .depend
EDIT: If you want this even more generic, you can replace the SOURCE:= line with:
SOURCES:=$(wildcard *.c)
This makefile will then simply build TARGET from all .c files in the current directory.
One thing I would highly suggest here would be to add a clean target that deletes all your intermediate files (probably all the .o files), like so:
clean:
rm *.o
For extra credit, put all your *.o files in a make variable, and use that variable as the target of the run rule, and after the rm command above.
The reason I want you to do this is for debugging purposes. It could be that you have one of the above rules wrong, but since you already built all your .o files once, it is just picking up an old one every time. If you do a make clean before your build, it will catch that.

Resources