Archiv rubriky: programovani

Python: kompilace do nativniho kodu platformy

Python je momentalne muj nejoblibenejsi jazyk. Je rychly na prototypovani, umoznuje psat kratke skripty, velke GUI aplikace, webove stranky,…
Jednou z jeho nejvetsich (ne)vyhod je, ze jde o interpretovany jazyk. Tudiz je pomalejsi, nez jazyky kompilovane a kazdy muze videt zdrojovy kod.

Problem se nastesti da relativne snadno vyresit kompilaci.

Nebudu to rozebirat nijak do hloubky. Kdo chce podrobnosti, odkazu ho na pouzite zdroje v zaveru a na Google. Jde pouze o ukazani moznosti.

Prvni ukazka. Jednoduchy program na vypis aktualniho casu. Po spusteni jako samostatny program vypise cas a ukonci se. Pri importu jako modul v pythonu nevypise nic, ceka na zavolani funkce cas().

from datetime import datetime
 
def mojeFunkce(cas):
        print "Je %s hodin." % cas
       
def cas():
    hodiny = datetime.now().strftime('%H:%M:%S')
    mojeFunkce(hodiny)

if __name__ == '__main__':
    print "_RUN_"
    cas()
else:
    print "import"
martin@martin:~$ cython --embed prvni.py
martin@martin:~$ gcc prvni.c -I/usr/include/python2.7 -lpython2.7 -o prvni
martin@martin:~$ s -lh
celkem 172K
-rwxr-xr-x 1 martin martin  48K pro  8 13:03 prvni
-rw-r--r-- 1 martin martin 112K pro  8 13:03 prvni.c
-rw-r--r-- 1 martin martin  268 pro  8 13:02 prvni.py
-rw-r--r-- 1 martin martin  541 pro  8 13:02 prvni.pyc
martin@martin:~$ strip prvni
martin@martin:~$ ls -lh
celkem 164K
-rwxr-xr-x 1 martin martin  37K pro  8 13:03 prvni
-rw-r--r-- 1 martin martin 112K pro  8 13:03 prvni.c
-rw-r--r-- 1 martin martin  268 pro  8 13:02 prvni.py
-rw-r--r-- 1 martin martin  541 pro  8 13:02 prvni.pyc
martin@martin:~$ ./prvni 
_RUN_
Je 13:03:19 hodin
martin@martin:~$ python
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import prvni
>>> prvni.cas()
Je 13:03:33 hodin.
>>>
martin@martin:~$ ldd ./prvni
	linux-vdso.so.1 =>  (0x00007fff957fe000)
	libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f5f68c47000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5f68882000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f5f68663000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f5f6844a000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f5f68246000)
	libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f5f68042000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5f67d3c000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f5f691db000)
martin@martin:~$ 

 

Prvni prikaz (cython) vegeneruje z pythoniho zdrojoveho kodu C zdrojovy kod. Je tezko clovekem citelny, protoze je generovany. Parametr embed zajisti pridani main() funkce. Cython dokaze generovat C a C++ zdrojaky a pouzivat Python2, nebo Python3.

Pote je mozne vygenerovany C soubor pomoci gcc zkompilovat. Stripnuta binarka ma jenom 37kB.

Pri spusteni jako samotny program (./prvni) vypise _RUN_. Zavislosti (viz vystup ldd) jsou bezne linuxove knihovny plus navic libpython.

 

Druha ukazka je o trochu slozitejsi. Pomoci skvele knihovny requests stahne JSON z meteostanice a vypise aktualni teplotu.

import requests
import json
import time
import sys

try:
    debug = sys.argv[1]
except IndexError:
    debug = 0

def stahniData(debug):
    url = 'http://teplomer.jicin.cz/vystup-json.php'
    headers = {'user-agent': 'Python_test_app/0.0.1'}

    r = requests.get(url, headers=headers)

    odpovedText = r.text
    if debug:
        print odpovedText

    data = json.loads(odpovedText)
    teplota = str(data['teplota'])
    cas = str(data['cas'])

    return teplota, cas

while True:
    print 'Aktualne je {0}C, v {1}.'.format(*stahniData(debug))
    time.sleep(5)

 

martin@martin:~$ cython --embed druhy.py 
martin@martin:~$ gcc druhy.c -I/usr/include/python2.7 -lpython2.7 -O3 -o druhy
martin@martin:~$ ls -lh
celkem 340K
-rwxr-xr-x 1 martin martin  45K pro  8 13:12 druhy
-rw-r--r-- 1 martin martin 125K pro  8 13:12 druhy.c
-rw-r--r-- 1 martin martin  573 pro  8 13:11 druhy.py
martin@martin:~$ strip druhy
martin@martin:~$ ls -lh
celkem 328K
-rwxr-xr-x 1 martin martin  34K pro  8 13:13 druhy
-rw-r--r-- 1 martin martin 125K pro  8 13:12 druhy.c
-rw-r--r-- 1 martin martin  573 pro  8 13:11 druhy.py
martin@martin:~$ file druhy
druhy: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.24, BuildID[sha1]=4afeb4fa92c52bf9bb549e838525ca3416281bb9, stripped
martin@martin:~$ ldd ./druhy
	linux-vdso.so.1 =>  (0x00007fff0e72b000)
	libpython2.7.so.1.0 => /usr/lib/x86_64-linux-gnu/libpython2.7.so.1.0 (0x00007f9a35878000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a354b3000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a35294000)
	libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f9a3507b000)
	libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a34e77000)
	libutil.so.1 => /lib/x86_64-linux-gnu/libutil.so.1 (0x00007f9a34c73000)
	libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a3496d000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f9a35e0c000)
martin@martin:~$ ./druhy 
Aktualne je 7.1C, v 2015-12-08 13:12:35.
Aktualne je 7.1C, v 2015-12-08 13:12:35.
...
martin@martin:~$ ./druhy 1
{
   "teplota": 7.1,
   "vlhkost": null,
   "cas": "2015-12-08 13:12:35",
   "umisteni": "<a href="http://www.mapy.cz/s/hgUU">Zizkovo nam. 18</a>"
}

Aktualne je 7.1C, v 2015-12-08 13:12:35.
{
   "teplota": 7.1,
   "vlhkost": null,
   "cas": "2015-12-08 13:12:35",
   "umisteni": "<a href="http://www.mapy.cz/s/hgUU">Zizkovo nam. 18</a>"
}

Aktualne je 7.1C, v 2015-12-08 13:12:35.
...
martin@martin:~$

 

Mezi hodne zajimave vyhody kompilace Pythonu patri i mozne zrychleni. Python je dynamicky silne typovany jazyk. Neustale zjistovani a kontrola typu zpusobuje znatelne zpomaleni behu programu. Zvlast u nekterych vypoctu je rozdil obrovsky (proto se na vypocty ma pouzivat NumPy). Proto umoznuje Cython nadefinovat promennym datove typy.

Hodne zajimave je toto PDF. Urcite doporucuji precist. Z neho je take nasledujici ukazka:

def exp(x, terms = 50):
	sum = 0.
	power = 1.
	fact = 1.
	for i in range(terms):
	sum += power/fact
	power *= x
	fact *= i+1
	return sum
# doba behu pro 50 000 - 1,05s
	
def exp(double x, int terms = 50):
	cdef double sum
	cdef double power
	cdef double fact
	cdef int i
	sum = 0.
	power = 1.
	fact = 1.
	for i in range(terms):
	sum += power/fact
	power *= x
	fact *= i+1
	return sum
# doba behu pro 50 000 - 0,042s
# rozdil - 25x

 

Aneb jak se pise na oficialnim webu Cythonu: „Cython is Python with C data types“ (Cython je Python s C datovymi typy).

 

Pouzite zdroje:

Java: kompilace do nativniho kodu platformy

Programy v Jave, se na rozdil treba od C nekompiluji primo do nativniho kodu dane platformy, ale do bajt kodu (mezikodu). To muze velka (ne)vyhoda. zalezi na uhlu pohledu. Aplikace je pak multiplatformni, jde spustit na vsech OS, na ktere je portovana Java. Nevyhodnou je mozna trochu mensi rychlost (tohle tema nemam rad ;-)) a relativne snadna moznost dekompilovat zkompilovane class soubory. Malo se to vi a jeste min pouziva, ale i Java se do zkompilovat primo do nativniho kodu.

Celý příspěvek

Java generovani PDF: vytvoreni stitku na obalky z MS Excelu

Nedavno jsem si hral s generovanim PDF v Jave. Napsal jsem jednoduchy kod, ktery vygeneruje seznam adres na obalky do PDF. Data jsou pripavena v MS Excelu. Kod je priserne zpraseny, ale treba se nekomu pro inspiraci bude hodit 😉

Soubor s daty v MS Excelu musi mit presne stejne nadpisy bunek, jako je na obrazku. Tato slova jsou napevne zadratovana v kodu, samozrejme by nebyl problem udelat jednoduche GUI, ve kterem by si uzivatel naklikal, co chce. Data v Excelu je nutne ulozit do formatu CSV.

Vysledny CSV soubor vypada nasledovne:

Jmeno;Ulice;Mesto;Pohlavi
Karel Smolny;Nadrazni 123;Hradec Kralové III;muz
Marek Jurda;Studentska 95;Pardubice 2;muz
Pavla Novakova;Zerotinovo nam. 617/9;Brno;zena
Martin Pavlasek;17.listopadu 2172/15;Ostrava-Poruba;muz
Pavel Jirasek;Technicka 1902/2;Praha 6;muz

V Jave vyuzivam knihovnu JavaCSV z CSVReader.com pod LGPL 2 licenci na zpracovani CSV.
S knihovnou na praci s PDF je to mnohem horsi. ASi nejlepsi a nejznamejsi je iText. Jedna se o dualne licencovanou knihovnu. Prvni je licence AGPL 3 (GNU Affero General Public License) – ta je skoro nepouzitelna. Druha je placena, prave pro pripady, kdy nelze pouzit AGPL. 
Pred nekolika lety byla open source verze iText dostupna pod mnohem mene restriktivni licenci LGPL 2. Tato verze je uz dost obtizne k sehnani (prekvapive). Nastasti si mi ji podarilo najit na GitHubu. Pro kompatibilitu s novou knihovnou je urcena tato. Knihovna pod LGPL je uz nekolik let neudrzovana a neumi vsechno, co jeji aktualni verze!
Knihovny jako Apache PDFBox jsou jen pekne hracky bez dokumentace a tutorialu – ztrata casu se jimi vubec zabyvat…

Tady je ta prasarna: 


import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import com.csvreader.CsvReader;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;

public class AdresyNaObalky {	

    public static void main(String[] args) {

    	List adresy = new ArrayList();

    	try {
  
    		// ############### zpracovani CSV
    		
			CsvReader adresa = new CsvReader("data.csv", ';'); // oddelovac je strednik
			adresa.readHeaders();

	    	while (adresa.readRecord())
			{
				String jmeno = adresa.get("Jmeno"); // *musi* odpovidat nadpisum v excel tabulce
				String ulice = adresa.get("Ulice");
				String mesto = adresa.get("Mesto");			
				String pohlavi = adresa.get("Pohlavi");
				if (pohlavi.equals("muz")) {
					pohlavi = "Pan";				
				} else if (pohlavi.equals("zena")) {
					pohlavi = "Pani";					
				}
				System.out.println(pohlavi + ":" + jmeno + ":" + ulice + ":" + mesto);
				adresy.add(pohlavi + "\n" + jmeno + "\n" + ulice + "\n" + mesto); // pridame adresu
			}

	    	adresa.close();
		} catch (FileNotFoundException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
    	
    	// ############### zpracovani CSV   	
    	
    	
    	// ############### generovani PDF
    	   	
        Document document = new Document(PageSize.A4, 50, 20, 20, 20); // format papiru a okraje
        document.addAuthor("Martin Vancl"); // autor PDF
        document.addCreationDate(); // datum vytvoreni
        document.addTitle("Seznam adres pro tisk"); // nazev PDF dokumentu
        
        try {
            PdfWriter.getInstance(document,
                new FileOutputStream("adresy.pdf"));

            document.open();

            Font font1 = new Font(Font.TIMES_ROMAN, 15, Font.BOLD); // (family, size, style) - http://goo.gl/tm5DG

            int pocet = adresy.size();
            System.out.println(adresy.size());
            if ((pocet % 2) != 0) {
            	pocet++;	
			}
            
    		PdfPTable table = new PdfPTable(2);   
    		table.setWidthPercentage(100);
    		table.getDefaultCell().setBorder(Rectangle.NO_BORDER);

            for (String a : adresy) {
            	System.out.println(a);
            	PdfPCell bunka = new PdfPCell(new Paragraph(a, font1));
            	bunka.setBorder(Rectangle.NO_BORDER);
            	bunka.setPadding(20);
            	table.addCell(bunka);
			}
            if (pocet > adresy.size()) {
            	table.addCell("");				
			}

            document.add(table);
            
            document.close();

        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        // ############### generovani PDF
    }
}

 

Po spusteni vyplivne takovyto PDF soubor. JAR soubor ke stazeni. Komplet vse ke stazeni (tabulka v Excelu, zdrojak, knihovny, jar).

Vypis aktualni teploty v zadanem meste z Foreca.cz

Nekdy se muze hodit znat aktualni teplotu v urcitem meste. Nektera mesta, jako treba Jicin maji vlastni webovy teplomer. Na webu obechnanice.cz jsem se dozvedel o skvele sluzbe Foreca.cz. Problem je, ze krome aktualni teploty (tu potrebuju) vidim i spoustu dalsich udaju. Nastesti jde teplota ze stranky jednoduse vytahnout. 🙂

Celý příspěvek

Sleep ve Windows

Program sleep pocka pozadovanou dobu a ukonci se. V Linuxu casto pouzivam tento program pri psani skriptu. Ve Windows XP vsak nic podobneho neni. Co by kdo taky cekal od 8 let stareho operacniho systemu (XP je z 25.10.2001)?  Jak je to s Windows Vista nevim – nepouzivam.

V Linuxu je syntaxe nasledujici:
sleep 3 
   pocka 3s

 

I kdyz ve Windows XP nic podobneho neni, lze si pomoci jinak – programem PING. Kazdeho asi napadne, co ma ping a sleep spolecneho. Odpoved je jednoducha, jestlize se ping spusti se spravnymi parametry, funguje stejne jako sleep. Popis vsech parametru je na strankach Microsoftu.

ping 127.0.0.1 -n 3 -w 1000> nul
    pocka 3s

-w doba, po kterou bude ping cekat na odpoved. Zadava se v ms.
-n pocet pozadavku na odpoved. Jelikoz ma ping na localhost (127.0.0.1) prakticky nulovou odezvou, poslouzi jako parametr pro "uspani".

> nul  zahodit (nevypisovat) vypisy

 

Nejjednodussi je vytvorit program, ktery bude vyuzivat funkci sleep. V C by se to dalo napsat nejak podobne:

#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>  /* sleep() */

int main(int argc, char *argv[])
{  
  int cekat;

  if (argv[1] == NULL)
  {
    printf("Jako parametr uvedte cas v sekundach!\n");
  }
  else
  {                 
    while ((cekat = atoi(argv[1])) == 0);
    /* retezec z argv[1] se prevede na cislo */
     
    cekat = (cekat * 1000);
    /* funkci sleep se musi zadavat cas v [ms] => * 1000 */
     
    sleep(cekat); 
   }

   return 0;  
}

Pokud to nekdo chcete pouzit, tady je 32bit exe. Jestlize ma nekdo 64bit, nebo si to chce nejak upravit, tak tady je projekt v Dev-C++.

Program je dobre nakopirovat do C:\Windows, nebo do jine slozky, ktera je uvedena v promene PATH.