Jest to polecenie, które można uruchomić u dostawcy bezpłatnego hostingu OnWorks przy użyciu jednej z naszych wielu bezpłatnych stacji roboczych online, takich jak Ubuntu Online, Fedora Online, emulator online systemu Windows lub emulator online systemu MAC OS
PROGRAM:
IMIĘ
perlembed — jak osadzić Perla w programie C
OPIS
PREAMBUŁA
Czy chcesz:
Zastosowanie C od Perla?
Czytaj perlxstut, perlxs, h2xs, perlguts i perlapi.
Zastosowanie a Unix program od Perla?
Przeczytaj o cudzysłowach oraz o „system” i „exec” w perlfunc.
Zastosowanie Perl od Perla?
Przeczytaj o „do” w perlfunc i „eval” w perlfunc oraz o „require” w perlfunc i
„użyj” w perlfunc.
Zastosowanie C od C?
Przemyśl swój projekt.
Zastosowanie Perl od C?
Czytaj...
PLAN
· Kompilowanie programu w języku C
· Dodanie interpretera Perla do programu C
· Wywoływanie podprogramu Perla z programu C
· Ocena instrukcji Perla z programu C
· Wykonywanie dopasowań wzorców Perla i podstawień z programu C
· Zabawa ze stosem Perla w programie C
· Utrzymanie stałego tłumacza
· Utrzymanie wielu instancji interpreterów
· Używanie modułów Perla, które same korzystają z bibliotek C, z programu C
· Osadzanie Perla pod Win32
Kompilowanie Twój C program
Jeśli masz problemy z kompilacją skryptów zawartych w tej dokumentacji, nie jesteś sam. The
podstawowa zasada: KOMPILUJ PROGRAMY DOKŁADNIE W TYM SAMYM SPOSOBIE, W JAKI ZOSTAŁ Skompilowany Perl.
(Przepraszam, że krzyczę.)
Ponadto każdy program C korzystający z języka Perl musi zawierać łącze w pliku Perl biblioteka. Co to jest, pytasz?
Perl sam jest napisany w C; biblioteka Perla to zbiór skompilowanych programów w języku C
które zostały użyte do stworzenia pliku wykonywalnego Perla (/usr/bin/perl lub odpowiednik). (Następstwo:
nie możesz używać Perla z programu C, chyba że Perl został skompilowany na twoim komputerze, lub
zainstalowany poprawnie — dlatego nie powinieneś beztrosko kopiować plików wykonywalnych Perla z komputera
na maszynę bez kopiowania pliku lib informator.)
Kiedy używasz Perla z C, twój program C będzie - zwykle - alokował, „uruchamiał” i cofał alokację
Tłumacz Perla obiekt, który jest zdefiniowany przez bibliotekę Perla.
Jeśli twoja kopia Perla jest na tyle aktualna, że może zawierać tę dokumentację (wersja 5.002 lub
później), następnie biblioteka Perla (i ZEWNĘTRZNA.h oraz perl.h, które również będziesz potrzebować) will
znajdować się w katalogu wyglądającym tak:
/usr/local/lib/perl5/your_architecture_here/CORE
a może po prostu
/usr/local/lib/perl5/CORE
a może coś w tym stylu
/usr/opt/perl5/CORE
Wykonaj tę instrukcję, aby uzyskać wskazówkę dotyczącą tego, gdzie znaleźć CORE:
perl -MConfig -e 'drukuj $Config{archlib}'
Oto, jak skompilowałbyś przykład w następnej sekcji „Dodawanie interpretera Perla do
twój program C”, na moim Linuksie:
% gcc -O2 -Dbool=char -DHAS_BOOL -I/usr/local/include
-I/usr/local/lib/perl5/i586-linux/5.003/CORE
-L/usr/local/lib/perl5/i586-linux/5.003/CORE
-o interp interp.c -lperl -lm
(To wszystko w jednej linijce.) Na moim DEC Alpha ze starą wersją 5.003_05 inkantacja jest trochę
różne:
% cc -O2 -Olimit 2900 -DSTANDARD_C -I/usr/local/include
-I/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE
-L/usr/local/lib/perl5/alpha-dec_osf/5.00305/CORE -L/usr/local/lib
-D__LANGUAGE_C__ -D_NO_PROTO -o interp interp.c -lperl -lm
Jak dowiedzieć się, co dodać? Zakładając, że Twój Perl jest nowszy niż 5.001, wykonaj „perl -V”
polecenie i zwróć szczególną uwagę na informacje „cc” i „ccflags”.
Będziesz musiał wybrać odpowiedni kompilator (cc, gcci in.) dla Twojej maszyny: „perl
-MConfig -e 'print $Config{cc}'" powie ci, czego użyć.
Będziesz także musiał wybrać odpowiedni katalog biblioteki (/usr/local/lib/...) dla Twojego
maszyna. Jeśli Twój kompilator narzeka, że niektóre funkcje są niezdefiniowane lub że
nie mogę zlokalizować -lperl, musisz zmienić ścieżkę po „-L”. Jeśli narzeka
że nie może znaleźć ZEWNĘTRZNA.h oraz perl.h, musisz zmienić ścieżkę po „-I”.
Być może będziesz musiał dodać dodatkowe biblioteki. Które? Być może te wydrukowane przez
perl -MConfig -e 'drukuj $Config{libs}'
Pod warunkiem, że plik binarny Perla został poprawnie skonfigurowany i zainstalowany ExtUtils::Osadzanie moduł
ustalimy dla Ciebie wszystkie te informacje:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
Jeśli ExtUtils::Osadzanie moduł nie jest częścią twojej dystrybucji Perla, możesz go odzyskać
od http://www.perl.com/perl/CPAN/modules/by-module/ExtUtils/ (Jeśli ta dokumentacja przyszła
z dystrybucji Perla, to używasz wersji 5.004 lub nowszej i już ją masz.)
ExtUtils::Osadzanie kit na CPAN zawiera również cały kod źródłowy przykładów w tym
dokument, testy, dodatkowe przykłady i inne informacje, które mogą okazać się przydatne.
Dodawanie a Perl interpretator do Twój C program
W pewnym sensie perl (program C) jest dobrym przykładem osadzenia Perla (języka), tzw
Zademonstruję osadzanie za pomocą miniperlmain.c, zawarte w dystrybucji źródłowej.
Oto zła, nieprzenośna wersja miniperlmain.c zawierający najważniejsze elementy
osadzanie:
#włączać /* z dystrybucji Perla */
#włączać /* z dystrybucji Perla */
statyczny interpreter Perla *my_perl; /*** Interpreter Perla ***/
int main(int argc, char **argv, char **env)
{
PERL_SYS_INIT3(&argc,&argv,&env);
mój_perl = perl_alloc();
perl_construct(mój_perl);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_parse(my_perl, NULL, argc, argv, (char **)NULL);
perl_run(mój_perl);
perl_destruct(mój_perl);
bez perla(mój_perl);
PERL_SYS_TERM();
}
Zauważ, że nie używamy wskaźnika „env”. Zwykle przekazywany do „perl_parse” jako ostateczny
argument „env” zostaje tutaj zastąpiony przez „NULL”, co oznacza, że obecne środowisko tak zrobi
być użytym.
Makra PERL_SYS_INIT3() oraz PERL_SYS_TERM() zapewniają specyficzne dla systemu dostrojenie C
środowisko uruchomieniowe niezbędne do uruchomienia interpreterów Perla; należy je wywołać tylko raz
niezależnie od tego, ilu interpreterów utworzysz lub zniszczysz. Dzwonić PERL_SYS_INIT3() zanim
tworzysz swojego pierwszego tłumacza i PERL_SYS_TERM() po uwolnieniu ostatniego
interpretator.
Ponieważ PERL_SYS_INIT3() może zmienić „env”, bardziej odpowiednie może być podanie „env” jako pliku
argument drugi perl_parse().
Zauważ też, że bez względu na to, do jakich argumentów przekażesz perl_parse(), PERL_SYS_INIT3() musi
zostać wywołane na C Głównym () argc, argv i env i tylko raz.
Teraz skompiluj ten program (nazwę go interp.c) do pliku wykonywalnego:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
Po udanej kompilacji będziesz mógł skorzystać interp podobnie jak sam Perl:
% rozp
print "Całkiem dobry Perl \n";
wydrukuj „10890 - 9801 to”, 10890 - 9801;
Całkiem niezły Perl
10890 - 9801 to 1089
or
% interp -e 'printf("%x", 3735928559)'
martwa wołowina
Możesz także czytać i wykonywać instrukcje Perla z pliku, będąc w środowisku C
programu, umieszczając nazwę pliku w argument[1] przed telefonem perl_run.
powołanie a Perl podprogram od Twój C program
Aby wywołać poszczególne podprogramy Perla, możesz użyć dowolnego z dzwonić_* funkcje udokumentowane w
perlcall. W tym przykładzie użyjemy „call_argv”.
Pokazano to poniżej, w programie, który wywołam showtime.c.
#włączać
#włączać
statyczny interpreter Perla *my_perl;
int main(int argc, char **argv, char **env)
{
char *args[] = { NULL };
PERL_SYS_INIT3(&argc,&argv,&env);
mój_perl = perl_alloc();
perl_construct(mój_perl);
perl_parse(my_perl, NULL, argc, argv, NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
/*** pomijanie perl_run() ***/
call_argv("czas pokazu", G_DISCARD | G_NOARGS, argumenty);
perl_destruct(mój_perl);
bez perla(mój_perl);
PERL_SYS_TERM();
}
gdzie showtime jest podprogramem Perla, który nie przyjmuje żadnych argumentów (to jest G_NOARGS) i dla
które zignoruję wartość zwracaną (to jest G_ODKRYĆ). Te flagi i inne są
omówione w Perlcall.
Zdefiniuję showtime podprogram w pliku o nazwie showtime.pl:
print "Nie będę drukowany.";
podrzędny czas występu {
czas wydruku;
}
Wystarczająco proste. Teraz skompiluj i uruchom:
% cc -o showtime showtime.c \
`perl -MExtUtils::Embed -e ccopts -e ldopts`
% czasu występów showtime.pl
818284590
podając liczbę sekund, które upłynęły od 1 stycznia 1970 r. (początek
epoka Uniksa) i moment, w którym zacząłem pisać to zdanie.
W tym konkretnym przypadku nie musimy dzwonić perl_run, gdy ustawimy PL_exit_flag
PERL_EXIT_DESTRUCT_END, który wykonuje bloki END w perl_destruct.
Jeśli chcesz przekazać argumenty do podprogramu Perla, możesz dodać ciągi znaków do
Przekazano do zakończonej wartością „NULL” listę „args”. wywołanie_argv. Dla innych typów danych lub do sprawdzenia
zwrócą wartości, będziesz musiał manipulować stosem Perla. Zostało to pokazane w „Fiddler
ze stosem Perla z programu C”.
Ewaluacja a Perl oświadczenie od Twój C program
Perl udostępnia dwie funkcje API do oceny fragmentów kodu Perla. Są to „eval_sv” w
perlapi i „eval_pv” w perlapi.
Prawdopodobnie są to jedyne procedury, których będziesz potrzebować do wykonania fragmentów kodu Perla
z poziomu programu C. Twój kod może być tak długi, jak chcesz; może zawierać wiele
sprawozdania; może użyć „użyj” w perlfunc, „wymagaj” w perlfunc i „zrób” w perlfunc
aby dołączyć zewnętrzne pliki Perla.
ocena_pv pozwala nam ocenić poszczególne ciągi Perla, a następnie wyodrębnić zmienne w celu wymuszenia
na typy C. Poniższy program, ciąg.c, wykonuje trzy ciągi Perla, wyodrębniając plik an
„int” od pierwszego, „float” od drugiego i „char *” od trzeciego.
#włączać
#włączać
statyczny interpreter Perla *my_perl;
main (int argc, char **argv, char **env)
{
char *embedding[] = { "", "-e", "0" };
PERL_SYS_INIT3(&argc,&argv,&env);
mój_perl = perl_alloc();
perl_construct( mój_perl );
perl_parse(my_perl, NULL, 3, osadzanie, NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(mój_perl);
/** Traktuj $a jako liczbę całkowitą **/
eval_pv("$a = 3; $a**= 2", PRAWDA);
printf("a = %d\n", SvIV(get_sv("a", 0)));
/** Traktuj $a jako liczbę zmiennoprzecinkową **/
eval_pv("$a = 3.14; $a**= 2", PRAWDA);
printf("a = %f\n", SvNV(get_sv("a", 0)));
/** Traktuj $a jako ciąg **/
ewaluacja_pv(
"$a = 'rekcaH lreP rehtonA tsuJ'; $a = Reverse($a);", PRAWDA);
printf("a = %s\n", SvPV_nolen(get_sv("a", 0)));
perl_destruct(mój_perl);
bez perla(mój_perl);
PERL_SYS_TERM();
}
Wszystkie te dziwne funkcje with sv w ich nazwach pomagają konwertować skalary Perla na C
typy. Są one opisane w perlgutach i perlapi.
Jeśli skompilujesz i uruchomisz ciąg.c, zobaczysz rezultaty użycia SvIV() stworzyć
„int”, SvNV() aby utworzyć „pływak” i SvPV() aby utworzyć ciąg:
a = 9
a = 9.859600
a = Kolejny haker Perla
W powyższym przykładzie utworzyliśmy zmienną globalną do tymczasowego przechowywania obliczonej wartości
wartość naszego ocenianego wyrażenia. Jest to również możliwe i w większości przypadków jest lepszą strategią
z którego ma zostać pobrana wartość zwracana ewaluacja_pv() Zamiast. Przykład:
...
SV *val = eval_pv("reverse 'rekcaH lreP rehtonA tsuJ'", TRUE);
printf("%s\n", SvPV_nolen(wartość));
...
W ten sposób unikamy zanieczyszczenia przestrzeni nazw, nie tworząc zmiennych globalnych, co też zrobiliśmy
uprościliśmy również nasz kod.
Wykonywanie Perl wzorzec zapałki oraz substytucje od Twój C program
eval_sv() Funkcja pozwala nam oceniać ciągi kodu Perla, więc możemy je zdefiniować
funkcje, które używają go do „specjalizacji” w meczach i podstawieniach: mecz(), zastąpić(),
oraz mecze().
I32 dopasowanie (SV *string, char *wzorzec);
Biorąc pod uwagę ciąg znaków i wzór (np. „m/clasp/” lub „/\b\w*\b/”, które w twoim programie C
może pojawić się jako „/\\b\\w*\\b/”), mecz() zwraca 1, jeśli ciąg pasuje do wzorca i 0
Inaczej.
int substytut(SV **string, char *wzorzec);
Biorąc pod uwagę wskaźnik do „SV” i operację „=~” (np. „s/bob/robert/g” lub
„tr[AZ][az]”), zastąpić() modyfikuje ciąg znaków w „SV” zgodnie z
operację zwracającą liczbę dokonanych podstawień.
Dopasowania SSize_t (SV *string, char *wzorzec, AV ** dopasowania);
Biorąc pod uwagę „SV”, wzór i wskaźnik do pustego „AV”, mecze() ocenia „$string =~
$pattern” w kontekście listy i wypełnia zapałki z elementami tablicy, zwracając
liczba znalezionych dopasowań.
Oto przykładowy program, mecz.c, który wykorzystuje wszystkie trzy (tutaj zawinięto długie linie):
#włączać
#włączać
statyczny interpreter Perla *my_perl;
/** my_eval_sv(kod, kontrola_błędu)
** trochę jak eval_sv(),
** ale usuwamy zwracaną wartość ze stosu
**/
SV* my_eval_sv(SV *sv, I32 croak_on_error)
{
DSP;
zwrot SV*;
PUSHMARK(SP);
eval_sv(sv, G_SCALAR);
HISZPANIA;
retval = POP;
ODBICIE;
if (croak_on_error && SvTRUE(ERRSV))
rechot(SvPVx_nolen(ERRSV));
zwrot zwrotu;
}
/** dopasowanie (ciąg znaków, wzór)
**
** Używane do dopasowań w kontekście skalarnym.
**
** Zwraca 1, jeśli dopasowanie się powiodło; 0 w przeciwnym razie.
**/
Dopasowanie I32 (SV *string, char *wzorzec)
{
SV *polecenie = nowośćSV(0), *rewanż;
sv_setpvf(polecenie, "mój $string = '%s'; $string =~ %s",
SvPV_nolen(string), wzór);
retval = my_eval_sv(polecenie, PRAWDA);
SvREFCNT_dec(polecenie);
zwróć SvIV(retval);
}
/** substytut(ciąg znaków, wzór)
**
** Używane do =~ operacji, które
** zmodyfikuj ich lewą stronę (s/// i tr///)
**
** Zwraca liczbę udanych dopasowań oraz
** modyfikuje ciąg wejściowy, jeśli taki istniał.
**/
Zamiennik I32 (SV **string, char *wzorzec)
{
SV *polecenie = nowośćSV(0), *rewanż;
sv_setpvf(polecenie, "$string = '%s'; ($string =~ %s)",
SvPV_nolen(*string), wzór);
retval = my_eval_sv(polecenie, PRAWDA);
SvREFCNT_dec(polecenie);
*string = get_sv("string", 0);
zwróć SvIV(retval);
}
/** dopasowania (ciąg, wzór, dopasowania)
**
** Używane do dopasowań w kontekście listy.
**
** Zwraca liczbę dopasowań,
** i wypełnia ** dopasowania pasującymi podciągami
**/
SSize_t dopasowań (SV *string, char *pattern, AV **match_list)
{
SV *polecenie = nowośćSV(0);
SSize_t num_matches;
sv_setpvf(polecenie, "mój $string = '%s'; @array = ($string =~ %s)",
SvPV_nolen(string), wzór);
my_eval_sv(polecenie, PRAWDA);
SvREFCNT_dec(polecenie);
*match_list = get_av("tablica", 0);
liczba_dopasowań = av_top_index(*lista_dopasowań) + 1;
zwróć liczbę_dopasowań;
}
main (int argc, char **argv, char **env)
{
char *embedding[] = { "", "-e", "0" };
AV *lista_dopasowań;
I32 num_matches, i;
SV *tekst;
PERL_SYS_INIT3(&argc,&argv,&env);
mój_perl = perl_alloc();
perl_construct(mój_perl);
perl_parse(my_perl, NULL, 3, osadzanie, NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
tekst = nowośćSV(0);
sv_setpv(text, "Kiedy jest w sklepie spożywczym i "
„Rachunek wynosi około 76 centów, Maynard jest”
„świadomy, że jest coś, co *powinien* zrobić, coś”
„to pozwoli mu odzyskać jedną czwartą, ale ma”
„nie mam pojęcia *co*. Grzebie w swoim czerwonym wyciskaczu”
"portmonetka i daje chłopcu trzy dodatkowe grosze"
„jego dolara, mając nadzieję, że uda mu się trafić na właściwy”
„kwota. Chłopak oddaje mu dwa własne grosze”
„a potem wielka, błyszcząca dzielnica, która jest jego nagrodą”.
„-RICHH”);
if (match(text, "m/kwartał/")) /** Czy tekst zawiera słowo "ćwiartka"? **/
printf("dopasowanie: tekst zawiera słowo 'ćwiartka'.\n\n");
więcej
printf("dopasowanie: tekst nie zawiera słowa 'ćwiartka'.\n\n");
if (match(text, "m/ósmy/")) /** Czy tekst zawiera słowo "ósmy"? **/
printf("dopasowanie: tekst zawiera słowo 'ósmy'.\n\n");
więcej
printf("dopasowanie: tekst nie zawiera słowa 'ósmy'.\n\n");
/** Dopasowuje wszystkie wystąpienia /wi../ **/
num_matches = dopasowania(tekst, "m/(wi..)/g", &match_list);
printf("Dopasowania: m/(wi..)/g znaleziono %d dopasowań...\n", liczba_dopasowań);
for (i = 0; i < liczba_dopasowań; i++)
printf("dopasowanie: %s\n",
SvPV_nolen(*av_fetch(lista_dopasowań, i, FAŁSZ)));
printf("\n");
/** Usuń wszystkie samogłoski z tekstu **/
num_matches = substytut(&tekst, "s/[aeiou]//gi");
jeśli (liczba dopasowań) {
printf("substytut: s/[aeiou]//gi...%lu dokonano podstawień.\n",
(bez znaku długiego)num_matches);
printf("Teraz tekst to: %s\n\n", SvPV_nolen(tekst));
}
/** Próba podstawienia **/
if (!substitute(&text, "s/Perl/C/")) {
printf("zamiennik: s/Perl/C... Nie wykonano podstawienia.\n\n");
}
SvREFCNT_dec(tekst);
PL_perl_destruct_level = 1;
perl_destruct(mój_perl);
bez perla(mój_perl);
PERL_SYS_TERM();
}
który generuje wynik (ponownie zawinięto tutaj długie linie)
dopasowanie: tekst zawiera słowo „ćwiartka”.
dopasowanie: tekst nie zawiera słowa „ósmy”.
dopasowania: m/(wi..)/g znaleziono 2 dopasowania...
mecz: wola
pasuje do
substytut: s/[aeiou]//gi...139 dokonanych podstawień.
Teraz tekst brzmi: Whn hst cnvnnc str nd th bll cms t sm mnt lk 76 cnts,
Mynrd s wr tht thr s smthng h *shld* d, smthng tht wll nbl hm t gt
bck qrtr, bt h hs nd *wht*. H fmbls thrgh hs rd sqzy chngprs nd
gvs th by thr xtr pnns wth hs dllr, hpng tht h mght lck nt th crrct
mnt. Th by gvs hm bck tw f hs wn pnns nd thn th bg shny qrtr tht s
hs prz. -RCHH
substytut: s/Perl/C... Nie wykonano podstawienia.
Błahy w dotychczasowy Perl stos od Twój C program
Próbując wyjaśnić stosy, większość podręczników do informatyki mamrocze coś na ten temat
sprężynowe kolumny talerzy stołowych: ostatnią rzeczą, którą wepchnąłeś na stos, jest
pierwszą rzeczą, którą wyskakujesz. To wystarczy dla naszych celów: twój program w C będzie trochę naciskał
argumenty na „stos Perla”, zamknij oczy, aż wydarzy się magia, a następnie otwórz plik
wyniki — wartość zwracana przez podprogram Perla — poza stosem.
Najpierw musisz wiedzieć, jak konwertować typy C i Perl za pomocą nowySViv()
oraz sv_setnv() oraz nowyAV() i wszyscy ich przyjaciele. Są one opisane w perlgutach i
perlapi.
Następnie będziesz musiał wiedzieć, jak manipulować stosem Perla. Jest to opisane w perlcall.
Kiedy już to zrozumiesz, osadzenie Perla w C będzie łatwe.
Ponieważ C nie ma wbudowanej funkcji potęgowania liczb całkowitych, zróbmy Perla **
dostępny dla niego operator (jest to mniej przydatne, niż się wydaje, ponieważ Perl implementuje **
z literami C pow () funkcjonować). Najpierw utworzę funkcję potęgowania kodu pośredniego w power.pl:
wystawa dodatkowa {
mój ($a, $b) = @_;
zwróć $a ** $b;
}
Teraz utworzę program w C, moc.c, z funkcją PerlPower() który zawiera wszystkie
perlguts konieczne do wepchnięcia dwóch argumentów wystawa() i wyświetlić wartość zwracaną.
Weź głęboki oddech...
#włączać
#włączać
statyczny interpreter Perla *my_perl;
statyczna pustka
PerlPower(int a, int b)
{
DSP; /* inicjalizuj wskaźnik stosu */
WCHODZIĆ; /* wszystko, co zostało utworzone później */
ZAPISZTMPS; /* ...jest zmienną tymczasową. */
PUSHMARK(SP); /* zapamiętaj wskaźnik stosu */
XPUSHs(sv_2mortal(newSViv(a))); /* włóż bazę na stos */
XPUSHs(sv_2mortal(newSViv(b))); /* umieść wykładnik na stosie */
ODBICIE; /* ustaw lokalny wskaźnik stosu na globalny */
call_pv("wystawa", G_SCALAR); /* wywołaj funkcję */
HISZPANIA; /* odśwież wskaźnik stosu */
/* pobierz wartość zwracaną ze stosu */
printf („%d do %d potęgi to %d.\n”, a, b, POPi);
ODBICIE;
DARMOWETMPS; /* uwolnij zwracaną wartość */
WYJECHAĆ; /* ...i argumenty XPUSHed „śmiertelnik”.*/
}
int main (int argc, char **argv, char **env)
{
char *my_argv[] = { "", "power.pl" };
PERL_SYS_INIT3(&argc,&argv,&env);
mój_perl = perl_alloc();
perl_construct( mój_perl );
perl_parse(my_perl, NULL, 2, mój_argv, (char **)NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
perl_run(mój_perl);
PerlMoc(3, 4); /*** Oblicz 3 ** 4 ***/
perl_destruct(mój_perl);
bez perla(mój_perl);
PERL_SYS_TERM();
}
Skompiluj i uruchom:
% cc -o power power.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% moc
3 do potęgi czwartej to 4.
Utrzymywanie a uporczywy interpretator
Przy opracowywaniu interaktywnych i/lub potencjalnie długotrwałych aplikacji jest to dobry pomysł
utrzymanie stałego interpretera, zamiast przydzielania i konstruowania nowego
tłumacz wielokrotnie. Głównym powodem jest szybkość: ponieważ Perl będzie ładowany tylko
raz do pamięci.
Jednak podczas używania a. należy zachować większą ostrożność w przypadku przestrzeni nazw i zakresu zmiennych
stały tłumacz. W poprzednich przykładach używaliśmy zmiennych globalnych w pliku
domyślny pakiet „main”. Wiedzieliśmy dokładnie, jaki kod zostanie uruchomiony i założyliśmy, że możemy
unikaj zmiennych kolizji i skandalicznego wzrostu tabeli symboli.
Załóżmy, że Twoja aplikacja jest serwerem, na którym od czasu do czasu będzie uruchamiany kod Perla
dowolny plik. Twój serwer nie ma możliwości sprawdzenia, jaki kod będzie wykonywał. Bardzo
niebezpieczny.
Jeśli plik zostanie wciągnięty przez „perl_parse()”, skompilowany do nowo skonstruowanego interpretera,
a następnie wyczyszczone za pomocą „perl_destruct()”, jesteś chroniony przed większością
problemy z przestrzenią nazw.
Jednym ze sposobów uniknięcia kolizji przestrzeni nazw w tym scenariuszu jest przetłumaczenie nazwy pliku na
gwarantowana unikalna nazwa pakietu, a następnie skompiluj kod do tego pakietu za pomocą „eval”
w perlfunc. W poniższym przykładzie każdy plik zostanie skompilowany tylko raz. Albo
aplikacja może zdecydować się na wyczyszczenie tabeli symboli skojarzonej z plikiem po jego usunięciu
Nie jest już potrzebne. Używając „call_argv” w perlapi, wywołamy podprogram
„Embed::Persistent::eval_file” znajdujący się w pliku „persistent.pl” i przekaż
nazwa pliku i boolowska flaga czyszczenia/pamięci podręcznej jako argumenty.
Należy pamiętać, że proces będzie się rozwijał dla każdego używanego pliku. Ponadto,
mogą istnieć podprogramy „AUTOLOAD” i inne warunki, które powodują pojawienie się symbolu Perla
stół do uprawy. Możesz dodać logikę, która śledzi rozmiar procesu lub
uruchamia się ponownie po określonej liczbie żądań, aby zapewnić zużycie pamięci
zminimalizowane. Będziesz także chciał określić zakres swoich zmiennych za pomocą „my” w perlfunc, kiedy tylko
możliwe.
pakiet Osadź::Trwały;
#persistent.pl
używaj ścisłego;
nasza% pamięć podręczna;
użyj symbolu qw(delete_package);
sub ważna nazwa_pakietu {
mój($string) = @_;
$string =~ s/([^A-Za-z0-9\/])/sprintf("_%2x",unpack("C",$1))/eg;
# drugie przejście tylko dla słów zaczynających się od cyfry
$string =~ s|/(\d)|sprintf("/_%2x",unpack("C",$1))|np;
# Ubierz to jako prawdziwą nazwę pakietu
$string =~ s|/|::|g;
zwróć „Osadź”. $ciąg;
}
podplik_ewaluacyjny {
my($nazwa pliku, $usuń) = @_;
mój $pakiet = poprawna nazwa_pakietu($nazwa pliku);
mój $mtime = -M $nazwa pliku;
if(zdefiniowano $Cache{$package}{mtime}
&&
$Cache{$pakiet}{mtime} <= $mtime)
{
# skompilowaliśmy już ten podprogram,
# nie został zaktualizowany na dysku, nie ma już nic do zrobienia
print STDERR "już skompilowany $package->handler\n";
}
else {
lokalny *FH;
otwórz FH, $nazwa pliku lub die "otwórz '$nazwa pliku' $!";
lokalny($/) = undef;
mój $sub = ;
zamknij FH;
#zawiń kod w podprogram w naszym unikalnym pakiecie
mój $eval = qq{pakiet $pakiet; podrzędny program obsługi { $sub; }};
{
# ukryj nasze zmienne w tym bloku
mój($nazwa pliku, $mtime,$pakiet,$sub);
ewaluacja $ewaluacja;
}
giń $@ jeśli $@;
#cache go, chyba że będziemy czyścić za każdym razem
$Cache{$package}{mtime} = $mtime, chyba że $delete;
}
eval {$pakiet->obsługa;};
giń $@ jeśli $@;
usuń_pakiet($pakiet) jeśli $delete;
#spójrz, jeśli chcesz
#print Devel::Symdump->rnew($package)->as_string, $/;
}
1;
__KOŃCZYĆ SIĘ__
/* trwałe.c */
#włączać
#włączać
/* 1 = czyści tablicę symboli nazwy pliku po każdym żądaniu,
0 = nie
*/
#ifndef DO_CZYŚĆ
#zdefiniuj DO_CLEAN 0
#endif
#zdefiniuj ROZMIAR_BUFERA 1024
statyczny interpreter Perla *my_perl = NULL;
int
main(int argc, char **argv, char **env)
{
char *embedding[] = { "", "persistent.pl" };
char *args[] = { "", DO_CLEAN, NULL };
char nazwa pliku [BUFFER_SIZE];
int status wyjścia = 0;
PERL_SYS_INIT3(&argc,&argv,&env);
if((moj_perl = perl_alloc()) == NULL) {
fprintf(stderr, „brak pamięci!”);
wyjście(1);
}
perl_construct(mój_perl);
PL_oryginał = 1; /* nie pozwól, aby przypisanie $0 aktualizowało plik
proctitle lub osadzanie[0] */
status wyjścia = perl_parse(my_perl, NULL, 2, osadzanie, NULL);
PL_exit_flags |= PERL_EXIT_DESTRUCT_END;
if(!exitstatus) {
stan wyjścia = perl_run(mój_perl);
while(printf("Podaj nazwę pliku: ") &&
fgets(nazwa pliku, ROZMIAR_BUFERA, stdin)) {
nazwapliku[strlen(nazwa pliku)-1] = '\0'; /* pasek \n */
/* wywołanie podprogramu,
przekazując mu nazwę pliku jako argument */
args[0] = nazwa pliku;
call_argv("Osadź::Persistent::eval_file",
G_ODRZUĆ | G_EVAL, argumenty);
/* sprawdź $@ */
if(SvTRUE(ERRSV))
fprintf(stderr, "błąd oceny: %s\n", SvPV_nolen(ERRSV));
}
}
PL_perl_destruct_level = 0;
perl_destruct(mój_perl);
bez perla(mój_perl);
PERL_SYS_TERM();
wyjście(stan wyjścia);
}
Teraz skompiluj:
% cc -o trwałe trwałe.c \
`perl -MExtUtils::Embed -e ccopts -e ldopts`
Oto przykładowy plik skryptu:
#test.pl
mój $string = „cześć”;
foo($string);
sub foo {
print "foo mówi: @_\n";
}
Teraz uruchom:
% uporczywy
Wpisz nazwę pliku: test.pl
foo mówi: cześć
Wpisz nazwę pliku: test.pl
już skompilowany Embed::test_2epl->handler
foo mówi: cześć
Wpisz nazwę pliku: ^C
Egzekucja of KONIEC Bloki
Tradycyjnie bloki END były wykonywane na końcu perl_run. To powoduje
problemy dla aplikacji, które nigdy nie wywołują perl_run. Od wersji Perl 5.7.2 możesz określić
„PL_exit_flags |= PERL_EXIT_DESTRUCT_END”, aby uzyskać nowe zachowanie. Umożliwia to również
uruchomienie bloków END, jeśli perl_parse nie powiedzie się, a „perl_destruct” zwróci wyjście
wartość.
$0 Zadania
Kiedy skrypt Perla przypisuje wartość $0, środowisko wykonawcze Perla spróbuje ustawić tę wartość
pojawi się jako nazwa programu zgłoszona przez „ps”, aktualizując pamięć wskazywaną przez argv
przekazany do perl_parse() a także wywoływanie funkcji API, takich jak setproctitle() tam, gdzie to możliwe.
To zachowanie może nie być odpowiednie podczas osadzania Perla i można je wyłączyć
przypisując wcześniej wartość 1 zmiennej „PL_origalen”. perl_parse() nazywa się.
trwałe.c powyższy przykład prawdopodobnie spowoduje wystąpienie błędu segfault, gdy do którego przypisano $0
jeśli "PL_origalen = 1;" przypisanie zostaje usunięte. Dzieje się tak, ponieważ Perl będzie próbował pisać do
pamięć tylko do odczytu ciągów „embedding[]”.
Utrzymywanie wielokrotność interpretator instancje
Niektóre rzadkie aplikacje będą musiały utworzyć więcej niż jednego tłumacza podczas sesji.
Taka aplikacja może sporadycznie decydować się na zwolnienie jakichkolwiek zasobów powiązanych z
interpretator.
Program musi zadbać o to, aby tak się stało zanim następny tłumacz to
zbudowana. Domyślnie, gdy Perl nie jest zbudowany z żadnymi specjalnymi opcjami, global
zmienna „PL_perl_destruct_level” jest ustawiona na 0, ponieważ dodatkowe czyszczenie zwykle nie jest potrzebne
gdy program tworzy tylko jeden interpreter w całym swoim życiu.
Ustawienie „PL_perl_destruct_level” na 1 sprawia, że wszystko jest czyste:
jednocześnie(1) {
...
/* zresetuj tutaj zmienne globalne za pomocą PL_perl_destruct_level = 1 */
PL_perl_destruct_level = 1;
perl_construct(mój_perl);
...
/* wyczyść i zresetuj _wszystko_ podczas perl_destruct */
PL_perl_destruct_level = 1;
perl_destruct(mój_perl);
bez perla(mój_perl);
...
/* zróbmy to jeszcze raz! */
}
Kiedy perl_destruct() zostanie wywołane, drzewo analizy składni interpretera i tablice symboli
wyczyszczone, a zmienne globalne zresetowane. Drugie zadanie dot
„PL_perl_destruct_level” jest potrzebny, ponieważ perl_construct resetuje go do 0.
Załóżmy teraz, że mamy więcej niż jedną instancję interpretera uruchomioną w tym samym czasie. To jest
wykonalne, ale tylko jeśli użyłeś opcji Konfiguruj "-Dusemultiplicity" lub opcji
„-Dusethreads -Duseithreads” podczas budowania Perla. Domyślnie włączenie jednego z nich
Konfiguracja opcji ustawia zmienną globalną dla każdego interpretera „PL_perl_destruct_level” na 1,
dzięki czemu dokładne czyszczenie jest automatyczne i inicjowane są zmienne interpretera
prawidłowo. Nawet jeśli nie zamierzasz uruchamiać dwóch lub więcej tłumaczy jednocześnie, ale
aby uruchamiać je sekwencyjnie, jak w powyższym przykładzie, zaleca się budowanie Perla
opcję „-Dusemultiplicity”, w przeciwnym razie niektóre zmienne interpretera mogą nie zostać zainicjowane
poprawnie pomiędzy kolejnymi uruchomieniami, a aplikacja może ulec awarii.
Zobacz także „Interfejsy systemowe obsługujące wątki” w perlxs.
Użycie „-Dusethreads -Duseithreads” zamiast „-Dusemultiplity” jest bardziej odpowiednie, jeśli
zamierzasz uruchomić wiele interpreterów jednocześnie w różnych wątkach, ponieważ to
umożliwia obsługę łączenia bibliotek wątków systemu z interpreterem.
Spróbujmy:
#włączać
#włączać
/* zamierzamy osadzić dwa interpretery */
#define SAY_HELLO "-e", "print qq(Cześć, jestem $^X\n)"
int main(int argc, char **argv, char **env)
{
Interpreter Perla *one_perl, *two_perl;
char *one_args[] = { "jeden_perl", POWIEDZ_HELLO };
char *two_args[] = { "dwa_perl", POWIEDZ_Witajcie };
PERL_SYS_INIT3(&argc,&argv,&env);
jeden_perl = perl_alloc();
two_perl = perl_alloc();
PERL_SET_CONTEXT(jeden_perl);
perl_construct(jeden_perl);
PERL_SET_CONTEXT(dwa_perle);
perl_construct(dwa_perl);
PERL_SET_CONTEXT(jeden_perl);
perl_parse(one_perl, NULL, 3, one_args, (char **)NULL);
PERL_SET_CONTEXT(dwa_perle);
perl_parse(dwa_perl, NULL, 3, dwa_args, (char **)NULL);
PERL_SET_CONTEXT(jeden_perl);
perl_run(jeden_perl);
PERL_SET_CONTEXT(dwa_perle);
perl_run(dwa_perl);
PERL_SET_CONTEXT(jeden_perl);
perl_destruct(jeden_perl);
PERL_SET_CONTEXT(dwa_perle);
perl_destruct(dwa_perl);
PERL_SET_CONTEXT(jeden_perl);
perl_free(jeden_perl);
PERL_SET_CONTEXT(dwa_perle);
perl_free(dwa_perl);
PERL_SYS_TERM();
}
Zwróć uwagę na połączenia do PERL_SET_CONTEXT(). Są one niezbędne do zainicjowania stanu globalnego
śledzi, który interpreter jest „bieżący” w konkretnym procesie lub wątku
to może go uruchomić. Należy go zawsze używać, jeśli masz więcej niż jednego tłumacza
i wykonują wywołania API Perla na obu interpreterach w sposób przeplatany.
PERL_SET_CONTEXT(interp) należy również wywołać za każdym razem, gdy wątek używa „interp”.
nie utworzył go (używając albo perl_alloc()lub bardziej ezoteryczne perl_clone()).
Skompiluj jak zwykle:
% cc -o krotność krotność.c \
`perl -MExtUtils::Embed -e ccopts -e ldopts`
Uruchom, uruchom:
% krotności
Cześć, jestem one_perl
Cześć, jestem two_perl
Korzystanie z Perl moduły który sami posługiwać się C biblioteki, od Twój C program
Jeśli bawiłeś się powyższymi przykładami i próbowałeś osadzić skrypt, który używać()w Perlu
moduł (np Gniazdo), która sama korzysta z biblioteki C lub C++, prawdopodobnie tak się stało:
Nie można załadować modułu Socket, ładowanie dynamiczne nie jest dostępne w tym Perlu.
(Być może będziesz musiał zbudować nowy plik wykonywalny Perla, który obsługuje albo
ładowanie dynamiczne lub moduł Socket jest z nim statycznie połączony.)
Co się stało?
Twój tłumacz nie wie, jak samodzielnie komunikować się z tymi rozszerzeniami. A
trochę kleju pomoże. Do tej pory dzwoniłeś perl_parse(), przekazując mu NULL dla
drugi argument:
perl_parse(my_perl, NULL, argc, mój_argv, NULL);
W tym miejscu można wstawić kod kleju, aby utworzyć początkowy kontakt pomiędzy Perlem i
połączone procedury C/C++. Przyjrzyjmy się niektórym fragmentom perlmain.c aby zobaczyć, jak radzi sobie Perl
to:
statyczna nieważność xs_init (pTHX);
EXTERN_C void boot_DynaLoader (pTHX_ CV* cv);
EXTERN_C void boot_Socket (pTHX_ CV* cv);
EXTERN_C nieważne
xs_init(pTHX)
{
znak *plik = __PLIK__;
/* DynaLoader to przypadek specjalny */
newXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, plik);
newXS("Socket::bootstrap", boot_Socket, plik);
}
Mówiąc najprościej: dla każdego rozszerzenia powiązanego z plikiem wykonywalnym Perla (ustalonym podczas jego pliku wykonywalnego).
wstępna konfiguracja na komputerze lub podczas dodawania nowego rozszerzenia), podprogram Perla
został stworzony w celu uwzględnienia procedur rozszerzenia. Zwykle ten podprogram ma nazwę
Moduł::bootstrap() i jest wywoływany, gdy mówisz posługiwać się Moduł. To z kolei łączy się z
XSUB, moduł_bootowy, który tworzy odpowiednik w języku Perl dla każdego elementu XSUB rozszerzenia.
Nie martw się o tę część; zostaw to xsubpp i autorzy rozszerzeń. Jeżeli twój
rozszerzenie jest ładowane dynamicznie, DynaLoader tworzy Moduł::bootstrap() dla ciebie na
latać. Tak naprawdę, jeśli masz działający DynaLoader, rzadko kiedy zachodzi potrzeba łączenia się
wszelkie inne rozszerzenia statycznie.
Kiedy już będziesz miał ten kod, wrzuć go do drugiego argumentu perl_parse():
perl_parse(moj_perl, xs_init, argc, moj_argv, NULL);
Następnie skompiluj:
% cc -o interp interp.c `perl -MExtUtils::Embed -e ccopts -e ldopts`
% rozp
użyj gniazda;
użyj SomeDynamicallyLoadedModule;
print "Teraz mogę używać rozszerzeń!\n"'
ExtUtils::Osadzanie może również zautomatyzować pisanie pliku xs_init kod kleju.
% perl -MExtUtils::embed -e xsinit -- -o perlxsi.c
% cc -c perlxsi.c `perl -MExtUtils::Embed -e ccopts`
% cc -c interp.c `perl -MExtUtils::Embed -e ccopts`
% cc -o interp perlxsi.o interp.o `perl -MExtUtils::Embed -e ldopts`
Więcej szczegółów znajdziesz w perlxs, perlguts i perlapi.
Korzystanie z osadzone Perl w POSIX locales
(Zobacz perllocale, aby uzyskać informacje na ten temat.) Kiedy zwykle uruchamia się interpreter Perla,
informuje system, że chce użyć domyślnych ustawień regionalnych systemu. Dzieje się tak często, ale nie
koniecznie ustawienia regionalne „C” lub „POSIX”. Brakuje „użyj ustawień regionalnych” w kodzie Perla
przeważnie nie ma żadnego efektu (ale zobacz „Nie w zakresie „użyj ustawień regionalnych”” w perllocale).
Ponadto nie ma problemu, jeśli ustawienia regionalne, których chcesz używać w osadzonym Perlu, to
taki sam jak domyślny system. Jednak to nie działa, jeśli skonfigurowałeś i chcesz używać
ustawienia regionalne, które nie są domyślnymi ustawieniami systemu. Począwszy od Perla v5.20, możesz rozpoznać
osadzonego interpretera Perla, że ustawienia regionalne są już poprawnie skonfigurowane i pomiń to
własną normalną inicjalizację. Pomija zmienną środowiskową
Ustawiono „PERL_SKIP_LOCALE_INIT” (nawet jeśli jest ustawione na 0 lub „”). Perl, który ma taką możliwość
zdefiniuje symbol preprocesora C „HAS_SKIP_LOCALE_INIT”. Pozwala to na kod, który ma
do pracy z wieloma wersjami Perla, aby obejść problem w obliczu pliku
wcześniej Perla.
Ukrywanie Perł_
Jeśli całkowicie ukryjesz krótkie formy publicznego API Perla, dodaj -DPERL_NO_SHORT_NAMES
do flag kompilacji. Oznacza to, że na przykład zamiast pisać
warn("%d butelek piwa na ścianie", liczba butelek);
będziesz musiał napisać wyraźny pełny formularz
Perl_warn(aTHX_ "%d butelek piwa na ścianie", liczba butelek);
(Zobacz „Tło i PERL_IMPLICIT_CONTEXT” w perlgutach, aby uzyskać wyjaśnienie
„aTHX_”. ) Ukrywanie krótkich form jest bardzo przydatne, aby uniknąć wszelkiego rodzaju nieprzyjemnych (C
preprocesor lub inny) powoduje konflikty z innymi pakietami oprogramowania (Perl definiuje około 2400
API o tych krótkich nazwach, weź lub zostaw kilkaset, więc na pewno jest na to miejsce
konflikt.)
MORAŁ
Czasami możesz napisać szybciej kod w C, ale zawsze możesz napisać kod szybciej w Perlu.
Ponieważ możesz używać jednego od drugiego, łącz je według własnego uznania.
Korzystaj z perlembed online, korzystając z usług onworks.net
