Sorry, this entry is only available in Polski.
I’ve come across the following error during the process of linking the c with floating point arithmetics (atof, exactly):
/opt/cross/avr/lib/gcc/avr/4.3.3/../../../../avr/lib/avr5/libc.a(cmpsf2.o):../../../libm/fplib/cmpsf2.S:58: multiple definition of `__ltsf2' /opt/cross/avr/lib/gcc/avr/4.3.3/avr5/libgcc.a(_lt_sf.o):/usr/src/packages/BUILD/build/avr/avr5/libgcc/../../.././gcc/fp-bit.c:1287: first defined here /opt/cross/avr/lib/gcc/avr/4.3.3/../../../../avr/lib/avr5/libc.a(floatsisf.o):../../../libm/fplib/floatsisf.S:46: multiple definition of `__floatsisf' /opt/cross/avr/lib/gcc/avr/4.3.3/avr5/libgcc.a(_si_to_sf.o):/usr/src/packages/BUILD/build/avr/avr5/libgcc/../../.././gcc/fp-bit.c:1349: first defined here
Solution is to add the -lm switch as a last one in the linker command line.
My example Makefile, in which the problem was avoided:
FILE=gps MCU=atmega328p CFLAGS=-g -mmcu=$(MCU) -Wall -Wstrict-prototypes -Os -mcall-prologues -lm PORT=/dev/ttyUSB0 DUDEOPTS=-c arduino -p m328p -P $(PORT) -b 57600 all: $(FILE).hex help: @echo "Say \"make\" to compile (create .hex file)." @echo "Say \"make load\" to transfer program to microcontroller." @echo "Say \"make clean\" to delete all build files." $(FILE).hex : $(FILE).out avr-objcopy -R .eeprom -O ihex $(FILE).out $(FILE).hex $(FILE).out : $(FILE).o avr-gcc $(CFLAGS) -o $(FILE).out -Wl,-Map,$(FILE).map $(FILE).o -lm $(FILE).o : $(FILE).c avr-gcc $(CFLAGS) -Os -c $(FILE).c load: $(FILE).hex stty -F $(PORT) hupcl avrdude $(DUDEOPTS) -e -U flash:w:$(FILE).hex clean: rm -f *.o *.map *.out *.hex
Line, which had to be changed is highlighted.
Question: How to find all hard links to one file in a given file and do something with them (count, replace with symbolic links, delete or whatever)? We need to use a find command. But there are some problems with it:
- We can use
-links +1to find all files, which link count value is bigger than 1 (knowing, that every file in *nix is just a hard link to a given inode, we look for files that have more than one hard link). But that would give us files that have links outside the given directory tree as well. - We can use a
whileloop to check all files found using a-links +1approach usingfindwith a-samefileswitch, but that would be really slow when given a big directory tree.
Solution? We have to find every tegular file (-type f) that have more than one hard link (-links +1). Cool, but find will print out those files in a rather random order. We need them sorted – so every link to a given inode would be next to each other. How to do that? find allows printing results not only in a simple way using -print, but gives us a more sophisticated way with -printf. Knowing that we can use -printf "%i %p\n" to print inode in front of the file path, and then use sort to achieve success.
Example code looks like that:
#!/bin/bash
find $1 -type f -links +1 -printf "%i %p\n" | sort | while read a
do
# $a == currently checked line
inode=`echo $a | cut -d' ' -f1`
path=`echo $a | cut -d' ' -f2`
done
Now, if current $inode differs from the one found in previous loop iteration, then we can be sure that we won’t find another link to that file. So, we have to add a little modification – for example, a global variable with last inode, and everything is cool again..
Why while and not for?
Difference is simple, but important. In the case of that loop:
for i in *
do
# do something
done
whole * lands in the command line. It may seem unimportant, but when there are a lot of files in * it may be a problem – length of a command line is limited after all. Let’s look at the while:
find $1 -print | while read variable
do
# do something
done
Looks more complicated, but it’s better. Here find result is not passed as a command line argument, but uses a pipeline to send it to while. Knowing, that pipeline length is practically unlimited, we are avoiding the for problem.
See also:
Sorry, this entry is only available in Polski.
Sorry, this entry is only available in Polski.
