A bit about

Hello, everyone! All you can see below is just my bank of information. Some material I've found in the fathomless net, some I've learned myself. Don't think all of the information here is right or actual, but may be it could be of use for you :) All feedback is welcome, especially constructive ones :)

Tuesday, April 29, 2008

How to know makefile name and targets

In lots of cases I had to know the name of the current makefile and targets, Make was called with. I expected that solution of these problems should be in special variables, however I couldn't find such variables even in GNU Make reference.

Why do I need to know such information on runtime? So, lets start with name of the current makefile.

MAKEFILE_LIST - list of the currently used makefiles

Imagine that we have to do recursive call of Make to call different targets, with different variables. For example, I have a number of targets with the same actions, but with different paths. And I want to have one target that do these actions and another targets which call the first one with different MY_PATH values. In common case, the code will be:
all: t1 t2

t1:
$(MAKE) MY_PATH=~/component1 build
t2:
$(MAKE) MY_PATH=~/component2 build
build:
$(CC) -o $(MY_PATH)/binary source.c

It's working. But our makefile could be called other than "makefile". My solution is predefined variable MAKEFILE_LIST. It contains the list of makefiles used for build.
all: t1 t2

t1:
$(MAKE) -f $(MAKEFILE_LIST) MY_PATH=~/component1 build
t2:
$(MAKE) -f $(MAKEFILE_LIST) MY_PATH=~/component2 build
build:
$(CC) -o $(MY_PATH)/binary source.c

I've tested this code in different versions of Linux, MacOS and even under Cygwin. May be I'll find another, simpler way for recursive call, but at this moment I have only this one.

MAKECMDGOALS - list of the specified targets

Sometimes it happens, that different targets require different set of variables, defined by user. For instance, make src should export a repository tree to the current directory (prepare sources to build) and thus require a repository address and a revision. Also, make build should build these sources. May it require ARCH variable, which means target architecture. So, it's normal to check variables existence, but it's nonsense to make a user define architecture while exporting repository tree ;) That's why we should check only those variable, which are required by the selected target.
I found predefined variable MAKECMDGOALS investigating output of command $(warning $(.VARIABLES)) (see the GNU Make reference). In the end, let's try to write a little make, illustrating usage of this variable:
ALL=src build

ifeq ($(MAKECMDGOALS),)
MAKECMDGOALS=$(ALL)
endif

ifneq ($(filter $(MAKECMDGOALS), src),)
ifeq ($(REV),)
$(error REV variable should be defined)
endif
ifeq ($(SVN),)
$(error SVN variable should be defined)
endif
endif
ifneq ($(filter $(MAKECMDGOALS), build),)
ifeq ($(ARCH),)
$(error ARCH variable should be defined)
endif
endif

all: $(ALL)

src:
svn export -r $(REV) $(SVN)

build:
gcc -march=$(ARCH) test.c -o test


UPD: I missed this page, because thought that it's not the variable I need: http://www.gnu.org/software/automake/manual/make/MAKEFILE_005fLIST-Variable.html

Sunday, April 27, 2008

HTTP query from PHP

Here is a simple PHP script, which sends http request and reads output of the server. First of all it uses HTTP header to read amount of incoming data. But if there's no Content-Length field, the script reads until EOF.

<?
// just kind of query to Google's image search
$Artist = "Evanescence";
$Album = "Fallen";

$query = rawurlencode("\"".$Artist."\" \"".$Album."\" Cover");
// encode part of url (query string)
$query = "/images?gbv=2&hl=ru&newwindow=1&q=".$query;
// add HTTP request syntax
$query = "GET ".$query." HTTP/1.1\r\n\r\n";

// open socket
$google_sock = fsockopen(gethostbyname("images.google.ru") ,80, $errno, $errstr, 30);
if(!$google_sock)
die("Couldn't connect to images.google.com");

// send the query
fputs($google_sock, $query);

$html = ""; // clear html code
$html_length = 0; // length of html
$header_line = ""; // line of HTTP header
do
{
// get next line of HTTP header
fscanf($google_sock, "%[^\n]", $header_line);
// remove symbols like \r
$header_line = trim($header_line);

$header_name = trim(strtok($header_line, ":"));
if($header_name == "Content-Length")
$html_length = strtok(":");
}
while($header_line != "");

if($html_length > 0)
$html = fread($google_sock, $html_length);
else
{
while( !feof($google_sock) )
$html .= fread($google_sock, 4096);
}

fclose($google_sock);

echo $html;
?>

Tuesday, April 22, 2008

Vim syntax highlighting

In most configurations, by default, Vim highlights language or file specific syntax (if not, try using :syntax on. But it uses file's name or its extension to determine required syntax configuration. It's very comfortable, but in some cases we have to give a name to a file, which doesn't correspond contents of the file. Therefore, Vim can't correctly determine configuration. To do it manually one can use :set filetype=<...>

The list of available syntax highlightings can be found in /usr/share/vim/vim63/syntax, just look through file names.

Thursday, April 17, 2008

SVN and EOL style

Sometimes it happens that we should checkout or export file from repository with different End-Of-Line styles (0x0D 0x0A for Windows, 0x0A for Unix and 0x0D for MacOS). SVN let's you choose this style on checkout or export. All you need is to set property svn:eol-style=native and then point out required EOL in command line:

> svn export --native-eol CRLF <...> # For Windows
$ svn co --native-eol LF <...> # For Linux
$ svn export --native-eol CR <...> # For MacOS

Monday, April 14, 2008

BASH parameter parsing

I always tried to parse parameters, which were fed to my shell script by means of while loop. But when I was writing me next labwork, I noticed that my lecturer always use for loop. So I tried to compare speed of these two methods. I wrote the following two sctipts, which just iterate through parameter set:

test1.sh

#!/bin/bash
for i in $*; do
a=0; #just to do something
done;


test2.sh

#!/bin/bash
while [ "$1" != "" ]; do
shift;
a=0; # just to prevent time difference in this action during comparison
done


After that, I fed 1000 arguments to both scripts and run time tool:

$ time ./test1.sh `seq 1 1000`

real 0m0.177s
user 0m0.162s
sys 0m0.016s
$ time ./test2.sh `seq 1 1000`

real 0m0.304s
user 0m0.266s
sys 0m0.037s


Difference is amazing! But I thought that comparison "$1" = "" in the second script, would take much time, so I wrote the third variant of script:

#!/bin/bash
while [ $# -gt 0 ]; do
shift;
a=0;
done


run:

$ time ./test3.sh `seq 1 1000`

real 0m0.343s
user 0m0.316s
sys 0m0.026s


Look at this! In case of big number of arguments, it could take more time for shell to count them than just compare strings.

Resume: Ok, it's great and the first my thought was "forget about while loop for parameter parsing and use for", but... But I used to check the next parameter while parsing arguments which show a type of the next parameter (./test1.sh -o output_file). In this case it seems to be hard to use for. So my opinion is - keep in mind that shift operator is expensive, but kind of loop depends on current situation. K.I.S.S.! Don't make you code unreadable just to speed up it on ~0.1s :)

UPD:
Example with for doesn't allow us to feed arguments with spaces (like ./test1.sh "a b" or ./test1.sh a\ b)

Tuesday, April 8, 2008

Update: Unremovable spaces by means of CSS

This is an update for this post. I used white-space: pre to tell browser not to remove sequences of spaces. But while posting previous subject, I found that this option has a very big minus: text becomes "unwrapable" and is clipped by borders of the nearest html table. After looking through many sites I found a new option (which became available recently) - white-space: pre-wrap. It assumes that all spaces are indissoluble, but browser can wrap text on these spaces.

Monday, April 7, 2008

Make with N jobs

It's widely known that GNU Make can run with several jobs. User just have to pass -j key to Make command line. For example:

$ make -j 4 all

But lets write two very simple Makefiles and try recursive call of Make. Let's imagine we have src directory, and two source files - foo1.c and foo2.c in this directory. The first Makefile will be located in this src folder:

C=gcc
LINK=gcc
RM=rm -rf

BIN=foo
OBJ=foo1.o foo2.o

all: clean $(BIN)

$(BIN): $(OBJ)
$(LINK) $(OBJ) -o $@

$(OBJ): %.o : %.c
$(C) $^ -o $@

clean:
$(RM) $(BIN) $(OBJ)


Ok, this will give us binary file from sources. Now go to the parent folder and write the second Makefile:

all:
(cd src; make)


And that's all! Call Make from the parent directory and it will enter directory src and run another make there. But what if we set number of jobs?

$ make -j 2
make[1]: Entering directory '<...>/src'
make[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule.


Google says that Make passes additional information about jobserver on recursive call. But it does so only if he know that the child program is another Make. In our case he doesn't know. But let's do little change in the second Makefile:

all:
(cd src; $(MAKE))


Try running make with -j 2 again? Everything is Ok :) Because $(MAKE) is a special variable, which says that the child process is Make.

Friday, April 4, 2008

Magic The Gathering, deck

Yes! I received a deck of MTG cards at the beginning of this week. It's an Elvish one. It could be very powerful with Elf tokens. All in all, it's a very interesting game, I think. I don't wanna spend a lot of money for this, it's just for fun :)