How to include .h with makefile in linux? - c

I am writing software for ARM microcontrollers in C using linux and I'm not using an IDE. The reason for this is to learn how really low level stuff works. Now I want to include a .h file that has a corresponding .c file, in my main.c program the "usual way" by writing #include "timer.h". This of course requires me to somehow change the Makefile and or linkerscript!?
How can I do this?
Right now the file timer.h is included, but directly in the Makefile like this:
LD=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
CFLAGS=-mcpu=cortex-m3 -mthumb -g -std=c99 -Wall
LDFLAGS=-mcpu=cortex-m3 -mthumb -g -lgcc -lc -lcs3 -lcs3unhosted -lefm32gg -Llib
ASFLAGS=-mcpu=cortex-m3 -mthumb -g
LINKERSCRIPT=lib/efm32gg.ld
polling.bin : polling.elf
${OBJCOPY} -O binary $< $#
polling.elf : polling.o timer.o dac.o gpio.o interrupt_handlers.o
${LD} -T ${LINKERSCRIPT} $^ -o $# ${LDFLAGS}
%.o : %.c
${CC} ${CFLAGS} -c $< -o $#
.PHONY : pretty
pretty :
-indent *.c *.h
.PHONY : upload
upload :
-eACommander.sh -r --address 0x00000000 -f "polling.bin" -r
.PHONY : clean
clean :
-rm -rf *.o *.elf *.bin *.hex

Related

Makefile undefined reference to library

I know this is a very common question, but no matter where I looked I couldn't find a solution that worked.
I am writing an OS, and am also writing my own version of the c standard library, purely as a general interest type thing. I have my c standard library, which currently consists only of an incomplete string.h, in the sb_libc folder in the kernel's main directory. I can't use make to actually make the kernel if it includes my string.h header. I keep getting "undefined reference to strcpy". In order to test if I could include anything, I wrote two additional files, io.c and io_asm.s, and put their *.o files into the kernel's main directory. I can link those with the kernel just fine. Clearly, my library search paths are wrong in my make file. I'll post it below. If anyone can give me an idea on what I'm doing wrong, that would be great.
OBJECTS = loader.o io.o io_asm.o kmain.o ./sb_libc/string.o
CC = gcc
CFLAGS = -e kmain -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -nostartfiles -nodefaultlibs -Wall -Wextra -Werror -c -I./sb_libc/ -L./sb_libc/
LDFLAGS = -T link.ld -melf_i386 -I./sb_libc/ -L./sb_libc/
AS = nasm
ASFLAGS = -f elf
all: kernel.elf
kernel.elf: $(OBJECTS)
ld $(LDFLAGS) $(OBJECTS) -o kernel.elf
os.iso: kernel.elf
cp kernel.elf iso/boot/kernel.elf
genisoimage -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -A os -input-charset utf8 -quiet -boot-info-table -o os.iso iso
run: os.iso
bochs -f bochsrc.txt -q
%.o: %.c
$(CC) $(CFLAGS) $< -o $#
%.o: %.s
$(AS) $(ASFLAGS) $< -o $#
clean:
rm -rf *.o kernel.elf os.iso

Bypass default rule for make

I'm trying to compile several .c files through assembler:
%.S: %.c
$(XCC) -S -o $# $(XCFLAGS) -c $<
%.o: %.S
$(XCC) -o $# $(XCFLAGS) -c $<
test.a: test.o foo.o
$(LD) -o $# $^ $(XLDFLAGS)
$(XCC) is a cross-compile tool.
Actually, I see:
cc -c -o test0.o test0.c
cc -c -o foo.o foo.c
Native compilation runs instead of required cross compilation. I looks like some default rule for %.c to %.o translation is used instead of described chain rule.
If I change one pattern to direct description, compilation is ok:
test.S: test.c
$(XCC) -S -o $# $(XCFLAGS) -c $<
foo.S: foo.c
$(XCC) -S -o $# $(XCFLAGS) -c $<
%.o: %.S
$(XCC) -o $# $(XCFLAGS) -c $<
What is wrong with pattern chain? Is it possible to disable default rule for %.o ?
There is a default rule to generate .o files from .c files. That rule gets invoked when the first makefile is used.
You could add the following to the makefile to override the default rule:
%.o: %.c
$(XCC) -S -o $*.S $(XCFLAGS) -c $<
$(XCC) -o $# $(XCFLAGS) -c $*.S
You can also use:
%.o: %.c
without any recipes under it. This will invoke the other two rules to create the .S file and the .o file from there. However, it will delete the intermediate .S file after the .o is created. To prevent the .S file from getting deleted, you can use:
.PRECIOUS: test.S foo.S
You can read more on this subject at https://www.gnu.org/software/make/manual/html_node/Implicit-Rules.html#Implicit-Rules.
You can keep your rules and just cancel the builtin rule with %.o: %.c. See also this answer.

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.

Adapt Makefile for cross-compilation

I have a makefile that works fine when I compile using /usr/bin/gcc to compile it. However I'm trying to compile it using a crosstool-ng compiler. I've changed CC to the cross-compilers location, and added a prefix to the directory that holds the compiler, but I get an error compiling.
The Makefile is here (sorry, it's long):
CFLAGS ?= -Wall -O0 -ggdb3
PREFIX = /home/me/crosstool-ng-1.18.0/x-tools/i586-system-linux-gnu/
CC = /home/me/crosstool-ng-1.18.0/x-tools/i586-system-linux-gnu/bin/i586-system-linux-gnu-gcc
ALL_CFLAGS = $(CFLAGS) -D_GNU_SOURCE
.phony: all
all: food libfood.so.1.0.0 foo_query
.phony: tools
tool tools: libfood_print foo_print
.phony: install
install: libfood.so.1.0.0
cp libfood.so.1.0.0 $(PREFIX)/lib
cd $(PREFIX)/lib ; \
ln -sf libfood.so.1.0.0 libfood.so.1 ; \
ln -sf libfood.so.1 libfood.so
cp libfood.h $(PREFIX)/include
cp foo_data.h $(PREFIX)/include
cp food $(PREFIX)/bin
cp foo_query $(PREFIX)/bin
%.o: %.c
$(CC) $(ALL_CFLAGS) -c $<
food: food.o foo.o
$(CC) $(ALL_CFLAGS) -o $# $^ -lm -lpthread
libfood.so.1.0.0: libfood.o
$(CC) -shared -Wl,-soname,libfood.so.1 -o libfood.so.1.0.0 libfood.o
libfood_print: libfood_print.o
$(CC) $(ALL_CFLAGS) -o $# $^ -lfood
foo_print: foo_print.o foo.o
$(CC) $(ALL_CFLAGS) -o $# $^ -lm -lpthread
foo_query: foo_query.o
$(CC) $(ALL_CFLAGS) -o $# $^ -lfood
food.o: food.c foo.h foo_data.h
foo.o: foo.c foo.h foo_data.h
foo_print.o: foo_print.c foo_data.h
foo_query.o: foo_query.c foo_data.h
libfood.o: libfood.c libfood.h
$(CC) $(ALL_CFLAGS) -fPIC -c $<
foo_print.o: foo_print.c foo.h
.phony:clean
clean:
rm -rf *.o *~ food libfood.so.1.0.0 foo_print libfood_print foo_query
The error message I'm getting says cannot find -lfood
collect2: ld returned 1 exit status
If anyone could suggest a fix for this I'd be very grateful.
EDIT: My Solution:
I should probably have been clearer but this Makefile was being used to build a package that was included in buildroot. I tried the suggestion by Jonatan, but unfortunately I still got the same error. My workaround was to run buildroot using make -k, and then build again using make.
An easy way to solve this would be:
ALL_CFLAGS += -L$(PREFIX)/lib
If you really want to install your lib in the toolchain, you should look for the usr/lib directory, usually the path is TOOLCHAIN_DIR/TOOLCHAIN_PREFIX/sysroot/usr/lib
Check other binaries in the $(PREFIX)/lib directory, you will notice that they were compile to run in you host, and not in your target.
The files the compiler need to check dependencies, link, and execute in your target, are installed in the sysroot directory.

Resources