Bab 12. Pemrograman

Daftar Isi

12.1. Skrip shell
12.1.1. Kompatibilitas shell POSIX
12.1.2. Parameter shell
12.1.3. Kondisional Shell
12.1.4. Loop shell
12.1.5. Variabel lingkungan shell
12.1.6. Urutan pemrosesan baris perintah shell
12.1.7. Program utilitas untuk skrip shell
12.2. Scripting dalam bahasa yang diinterpretasi
12.2.1. Debugging kode bahasa yang diinterpretasi
12.2.2. Program GUI dengan skrip shell
12.2.3. Tindakan ubahan untuk filer GUI
12.2.4. Kegilaan skrip pendek Perl
12.3. Menuis kode dalam bahasa yang dikompilasi
12.3.1. C
12.3.2. Program C Sederhana (gcc)
12.3.3. Flex - Lex yang lebih baik
12.3.4. Bison - Yacc yang lebih baik
12.4. Alat analisis kode statis
12.5. Awakutu
12.5.1. Eksekusi gdb dasar
12.5.2. Debugging paket Debian
12.5.3. Mendapatkan backtrace
12.5.4. Perintah gdb tingkat lanjut
12.5.5. Periksa ketergantungan pada pustaka
12.5.6. Alat pelacakan panggilan dinamis
12.5.7. Men-debug Galat X
12.5.8. Alat deteksi kebocoran memori
12.5.9. Disassembly biner
12.6. Alat build
12.6.1. Make
12.6.2. Autotools
12.6.2.1. Mengkompilasi dan menginstal program
12.6.2.2. Menghapus instalasi program
12.6.3. Meson
12.7. Web
12.8. Terjemahan kode sumber
12.9. Membuat paket Debian

Saya memberikan beberapa petunjuk bagi orang untuk belajar pemrograman pada sistem Debian yang cukup untuk melacak kode sumber yang dikemas. Berikut adalah paket penting dan paket dokumentasi yang sesuai untuk pemrograman.

Referensi daring tersedia dengan mengetik "man nama" setelah memasang paket manpages dan manpages-dev. Referensi daring untuk alat GNU tersedia dengan mengetik "info nama_program" setelah memasang paket dokumentasi yang bersangkutan. Anda mungkin perlu memasukkan arsip contrib dan non-free selain arsip main karena beberapa dokumentasi GFDL tidak dianggap sesuai dengan DFSG.

Harap pertimbangkan untuk menggunakan alat sistem kontrol versi. Lihat Bagian 10.5, “Git”.

[Awas] Awas

Jangan gunakan "test" sebagai nama berkas uji yang dapat dieksekusi. "test" adalah shell builtin.

[Perhatian] Perhatian

Anda harus memasang program perangkat lunak yang langsung dikompilasi dari sumber ke "/usr/local" atau "/opt" untuk menghindari tabrakan dengan program sistem.

[Tip] Tip

Contoh kode untuk membuat "Song 99 Bottles of Beer" mestinya memberi Anda ide bagus tentang hampir semua bahasa pemrograman.

Skrip shell adalah berkas teks dengan bit eksekusi yang dihidupkan dan berisi perintah dalam format berikut.

#!/bin/sh
 ... command lines

Baris pertama menentukan interpreter shell yang membaca dan mengeksekusi isi berkas ini.

Reading shell scripts is the best way to understand how a Unix-like system works. Here, I give some pointers and reminders for shell programming. See "Shell Mistakes" (https://www.greenend.org.uk/rjk/2001/04/shell.html) to learn from mistakes.

Tidak seperti mode interaktif shell (lihat Bagian 1.5, “Perintah shell sederhana” dan Bagian 1.6, “Pemrosesan teks mirip Unix”), skrip shell sering menggunakan parameter, kondisional, dan loop.

Setiap perintah mengembalikan status keluar yang dapat digunakan untuk ekspresi bersyarat.

  • Sukses: 0 ("Benar/True")

  • Galat: bukan 0 ("Salah/False")

[Catatan] Catatan

"0" dalam konteks kondisional shell berarti "Benar", sedangkan "0" dalam konteks kondisional C berarti "Salah".

[Catatan] Catatan

"[" adalah setara dengan perintah test, yang mengevaluasi argumennya sampai "]" sebagai ekspresi bersyarat.

Idiom kondisionak dasar untuk diingat adalah sebagai berikut.

  • perintah && bila_sukses_jalankan_perintah_ini_juga || true"

  • "perintah || bila_tidak_sukses_jalankan_perintah_ini_juga || true"

  • Cuplikan skrip multi-baris sebagai berikut

if [ conditional_expression ]; then
 if_success_run_this_command
else
 if_not_success_run_this_command
fi

Di sini "|| true" di akhir diperlukan untuk memastikan skrip shell ini tidak keluar pada baris ini secara tidak sengaja ketika shell dipanggil dengan flag"-e".



Operator perbandingan integer aritmatika dalam ekspresi bersyarat adalah "-eq", "-ne", "-lt", "-le", "-gt", dan "-ge".

Shell memproses skrip kira-kira sebagai urutan berikut.

  • Shell membaca satu baris.

  • Shell mengelompokkan bagian dari baris sebagai satu token jika berada di dalam "…" atau '…'.

  • Shell memecah bagian lain dari suatu baris menjadi token dengan yang berikut.

    • Ruang kosong: spasi tab ganti baris

    • Karakter meta: < > | ; & ( )

  • Shell memeriksa kata tetapan untuk setiap token untuk menyesuaikan perilakunya jika tidak dalam "…" atau '…'.

    • kata tetapan: if then elif else fi for in while unless do done case esac

  • Shell mengekspansikan alias jika tidak dalam "…" atau '…'.

  • Shell mengekspansikan tilde jika tidak dalam "…" atau '…'.

    • "~" → direktori rumah pengguna saat ini

    • "~~pengguna" → direktori rumah pengguna

  • Shell mengekspansikan parameter ke nilainya jika tidak dalam '…'.

    • parameter: "$PARAMETER" atau "${PARAMETER} "

  • Shell mengekspansikan substitusi perintah jika tidak dalam '…'.

    • "$( command )" → keluaran dari "perintah"

    • "` perintah `" → keluaran dari "perintah"

  • Shell mengekspansikan pathname glob untuk mencocokkan nama berkas jika tidak dalam "…"" atau '…'.

    • * → sebarang karakter

    • ? → satu karakter

    • [...] → salah satu karakter dalam "..."

  • Shell mencari perintah dari yang berikut dan mengeksekusinya.

    • definisi fungsi

    • perintah builtin

    • berkas yang dapat dieksekusi dalam "$PATH"

  • Shell pergi ke baris berikutnya dan mengulangi proses ini lagi dari puncak urutan ini.

Kutip tunggal dalam kutip ganda tidak berpengaruh.

Mengeksekusi "set -x" di shell atau menjalankan shell dengan opsi "-x" membuat shell mencetak semua perintah yang dieksekusi. Ini sangat berguna untuk debugging.


Ketika Anda ingin mengotomatiskan tugas di Debian, Anda harus menulisnya dengan bahasa yang diintepretasi terlebih dahulu. Panduan untuk pilihan bahasa yang diinterpretasi adalah:

  • Gunakan dash, jika tugas sederhana yang menggabungkan program CLI dengan program shell.

  • Gunakan python3, jika tugas tidak sederhana dan Anda menulisnya dari awal.

  • Gunakan perl, tcl, ruby, ... jika sudah ada kode yang menggunakan salah satu bahasa ini di Debian yang perlu disentuh untuk melakukan tugas tersebut.

Jika kode yang dihasilkan terlalu lambat, Anda dapat menulis ulang hanya bagian penting untuk kecepatan eksekusi dalam bahasa yang dikompilasi dan memanggilnya dari bahasa yang ditafsirkan.

Skrip shell dapat diperbaiki untuk membuat program GUI yang menarik. Caranya adalah dengan menggunakan salah satu program dialog yang disebut alih-alih interaksi membosankan menggunakan perintah echo dan read.


Berikut adalah contoh program GUI untuk menunjukkan betapa mudahnya itu hanya dengan suatu skrip shell.

Skrip ini menggunakan zenity untuk memilih berkas (baku /etc/motd) dan menampilkannya.

Peluncur GUI untuk skrip ini dapat dibuat berikut Bagian 9.4.10, “Memulai program dari GUI”.

#!/bin/sh -e
# Copyright (C) 2021 Osamu Aoki <osamu@debian.org>, Public Domain
# vim:set sw=2 sts=2 et:
DATA_FILE=$(zenity --file-selection --filename="/etc/motd" --title="Select a file to check") || \
  ( echo "E: File selection error" >&2 ; exit 1 )
# Check size of archive
if ( file -ib "$DATA_FILE" | grep -qe '^text/' ) ; then
  zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
    --text="$(head -n 20 "$DATA_FILE")"
else
  zenity --info --title="Check file: $DATA_FILE" --width 640  --height 400 \
    --text="The data is MIME=$(file -ib "$DATA_FILE")"
fi

Pendekatan semacam ini untuk program GUI dengan skrip shell hanya berguna untuk kasus pilihan sederhana. Jika Anda ingin menulis program apa pun dengan kompleksitas, silakan pertimbangkan untuk menulisnya di platform yang lebih mampu.


Di sini, Bagian 12.3.3, “Flex - Lex yang lebih baik” dan Bagian 12.3.4, “Bison - Yacc yang lebih baik” disertakan untuk menunjukkan bagaimana program seperti kompiler dapat ditulis dalam bahasa C dengan menyusun deskripsi tingkat yang lebih tinggi ke dalam bahasa C.

Anda dapat mengatur lingkungan yang tepat untuk mengkompilasi program yang ditulis dalam bahasa pemrograman C dengan yang berikut.

# apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential

Paket libc6-dev, yaitu Pustaka GNU C, menyediakan pustaka standar C yang merupakan kumpulan berkas header dan pustaka fungsi yang digunakan oleh bahasa pemrograman C.

Lihat referensi untuk C dengan cara berikut.

  • "info libc" (referensi fungsi pustaka C)

  • gcc(1) dan "info gcc"

  • each_C_library_function_name(3)

  • Kernighan & Ritchie, "The C Programming Language", 2nd edition (Prentice Hall)

Flex adalah generator analisis leksikal cepat yang kompatibel dengan Lex.

Tutorial untuk flex(1) dapat ditemukan di "info flex".

Many simple examples can be found under "/usr/share/doc/flex/examples/". [7]

Beberapa paket menyediakan parser LR lookahead yang kompatibel dengan Yacc atau generator parser LALR di Debian.


Tutorial untuk bison(1) dapat ditemukan di"info bison".

Anda perlu menyediakan "main()" dan "yyerror()" Anda sendiri. "main()" memanggil "yyparse()" yang memanggil "yylex()", biasanya dibuat dengan Flex.

Here is an example to create a simple terminal calculator program.

Let's create example.y:

/* calculator source for bison */
%{
#include <stdio.h>
extern int yylex(void);
extern int yyerror(char *);
%}

/* declare tokens */
%token NUMBER
%token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU

%%
calc:
 | calc exp OP_EQU    { printf("Y: RESULT = %d\n", $2); }
 ;

exp: factor
 | exp OP_ADD factor  { $$ = $1 + $3; }
 | exp OP_SUB factor  { $$ = $1 - $3; }
 ;

factor: term
 | factor OP_MUL term { $$ = $1 * $3; }
 ;

term: NUMBER
 | OP_LFT exp OP_RGT  { $$ = $2; }
  ;
%%

int main(int argc, char **argv)
{
  yyparse();
}

int yyerror(char *s)
{
  fprintf(stderr, "error: '%s'\n", s);
}

Let's create, example.l:

/* calculator source for flex */
%{
#include "example.tab.h"
%}

%%
[0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; }
"+"    { printf("L: OP_ADD\n"); return OP_ADD; }
"-"    { printf("L: OP_SUB\n"); return OP_SUB; }
"*"    { printf("L: OP_MUL\n"); return OP_MUL; }
"("    { printf("L: OP_LFT\n"); return OP_LFT; }
")"    { printf("L: OP_RGT\n"); return OP_RGT; }
"="    { printf("L: OP_EQU\n"); return OP_EQU; }
"exit" { printf("L: exit\n");   return YYEOF; } /* YYEOF = 0 */
.      { /* ignore all other */ }
%%

Then execute as follows from the shell prompt to try this:

$ bison -d example.y
$ flex example.l
$ gcc -lfl example.tab.c lex.yy.c -o example
$ ./example
1 + 2 * ( 3 + 1 ) =
L: NUMBER = 1
L: OP_ADD
L: NUMBER = 2
L: OP_MUL
L: OP_LFT
L: NUMBER = 3
L: OP_ADD
L: NUMBER = 1
L: OP_RGT
L: OP_EQU
Y: RESULT = 9

exit
L: exit

Alat seperti Lint dapat membantu analisis kode statisotomatis.

Alat seperti indent dapat membantu peninjauan kode dengan memformat ulang kode sumber secara konsisten.

Alat seperti Ctags dapat membantu peninjauan kode dengan menghasilkan berkas indeks (atau tag) nama yang ditemukan dalam kode sumber.

[Tip] Tip

Mengonfigurasi penyunting favorit Anda (emacs atau vim) untuk menggunakan plugin mesin lint asinkron membantu penulisan kode Anda. Plugin ini menjadi sangat kuat dengan memanfaatkan Language Server Protocol. Karena mereka bergerak cepat, menggunakan kode hulu mereka, bukan paket Debian mungkin merupakan pilihan yang baik.

Tabel 12.12. Daftar alat untuk analisis kode statis

paket popcon ukuran deskripsi
vim-ale I:0 2591 Asynchronous Lint Engine untuk Vim 8 dan NeoVim
vim-syntastic I:3 1379 Hack pemeriksaan sintaks untuk vim
elpa-flycheck V:0, I:1 808 pemeriksaan sintaks sambil jalan modern untuk Emacs
elpa-relint V:0, I:0 147 Pencari kesalahan regex Emacs Lisp
cppcheck-gui V:0, I:1 7224 alat untuk analisis kode C/C++ statis (GUI)
shellcheck V:2, I:13 18987 alat lint untuk skrip shell
pyflakes3 V:2, I:15 20 pemeriksa pasif dari program Python 3
pylint V:4, I:20 2018 Pemeriksa statis kode python
perl V:707, I:989 673 interpreter dengan pemeriksa kode statis internal: B::Lint(3perl)
rubocop V:0, I:0 3247 Penganalisis kode statis Ruby
clang-tidy V:2, I:11 21 alat linter C++ berbasis clang
splint V:0, I:2 2320 alat untuk memeriksa secara statis program C untuk bug
flawfinder V:0, I:0 205 alat untuk memeriksa kode sumber C/C++ dan mencari kelemahan keamanan
black V:3, I:13 660 pemformat kode Python tanpa kompromi
perltidy V:0, I:4 2493 Pengindentasi dan pemformat ulang skrip Perl
indent V:0, I:7 431 program pemformatan kode sumber bahasa C
astyle V:0, I:2 785 Pengindentasi kode sumber untuk C, C++, Objective-C, C#, dan Java
bcpp V:0, I:0 111 pemercantik C(++)
xmlindent V:0, I:1 53 Pemformat ulang stream XML
global V:0, I:2 1908 Alat pencarian dan penelusuran kode sumber
exuberant-ctags V:2, I:20 341 membangun indeks berkas tag atas definisi kode sumber
universal-ctags V:1, I:11 3386 membangun indeks berkas tag atas definisi kode sumber

Debug adalah bagian penting dari kegiatan pemrograman. Mengetahui cara men-debug program membuat Anda pengguna Debian yang baik yang dapat menghasilkan laporan bug yang berarti.


Debugger utama pada Debian adalah gdb(1) yang memungkinkan Anda untuk menginspeksi program saat dijalankan.

Mari kita pasang gdb dan program terkait dengan yang berikut ini.

# apt-get install gdb gdb-doc build-essential devscripts

Tutorial yang baik dari gdb dapat ditemukan:

  • info gdb

  • "Debugging dengan GDB" di /usr/share/doc/gdb-doc/html/gdb/index.html

  • tutorial di web

Berikut adalah contoh sederhana menggunakan gdb(1) pada suatu "program" yang dikompilasi dengan opsi "-g" untuk menghasilkan informasi debugging.

$ gdb program
(gdb) b 1                # set break point at line 1
(gdb) run args           # run program with args
(gdb) next               # next line
...
(gdb) step               # step forward
...
(gdb) p parm             # print parm
...
(gdb) p parm=12          # set value to 12
...
(gdb) quit
[Tip] Tip

Banyak perintah gdb(1) dapat disingkat. Ekspansi tab bekerja seperti di shell.

Karena semua biner yang dipasang harus di-strip pada sistem Debian secara baku, sebagian besar simbol debug dihapus dalam paket normal. Untuk men-debug paket Debian dengan gdb(1), paket *-dbgsym perlu dipasang (misalnya coreutils-dbgsym dalam kasus coreutils). Paket sumber menghasilkan paket *-dbgsym secara otomatis bersama dengan paket biner normal dan paket debug tersebut ditempatkan secara terpisah dalam arsip debian-debug. Silakan merujuk ke artikel di Debian Wiki untuk informasi lebih lanjut.

Jika paket yang akan di-debug tidak menyediakan paket *-dbgsym, Anda perlu memasangnya setelah membangun kembali dengan yang berikut.

$ mkdir /path/new ; cd /path/new
$ sudo apt-get update
$ sudo apt-get dist-upgrade
$ sudo apt-get install fakeroot devscripts build-essential
$ apt-get source package_name
$ cd package_name*
$ sudo apt-get build-dep ./

Perbaiki bug jika diperlukan.

Bump versi paket ke yang tidak bertabrakan dengan versi Debian resmi, misalnya yang ditambahi "+debug1" ketika meng-compile ulang versi paket yang ada, atau yang ditambahi "~ pre1" ketika meng-compile versi paket yang belum pernah dirilis dengan yang berikut.

$ dch -i

Kompilasi dan instal paket beserta simbol debug dengan yang berikut ini.

$ export DEB_BUILD_OPTIONS="nostrip noopt"
$ debuild
$ cd ..
$ sudo debi package_name*.changes

Anda perlu memeriksa skrip build paket dan memastikan menggunakan "CFLAGS = -g -Wall" untuk mengkompilasi biner.

Ketika Anda mengalami crash program, melaporkan laporan kutu dengan informasi backtrace yang dipotong-dan-tempel adalah ide yang baik.

Backtrace dapat diperoleh dengan gdb(1) menggunakan salah satu pendekatan berikut:

Untuk pengulangan tak hingga atau situasi papan ketik beku, Anda dapat memaksa untuk program crash dengan menekan Ctrl-\ atau Ctrl-C atau mengeksekusi"kill -ABRT PID ". (Lihat Bagian 9.4.12, “Membunuh sebuah proses”)

[Tip] Tip

Seringkali, Anda melihat backtrace dimana satu atau lebih dari baris atas berada dalam "malloc()" atau"g_malloc()". Ketika ini terjadi, kemungkinan backtrace Anda tidak terlalu berguna. Cara termudah untuk menemukan beberapa informasi yang berguna adalah dengan mengatur variabel lingkungan "$MALLOC_CHECK_" ke nilai 2 (malloc(3)). Anda dapat melakukan ini saat sedang menjalankan gdb dengan melakukan hal berikut.

 $ MALLOC_CHECK_=2 gdb hello

Make adalah utilitas untuk memelihara kelompok program. Saat eksekusi make(1), make membaca berkas aturan, "Makefile", dan memperbarui target jika itu tergantung pada berkas prasyarat yang telah dimodifikasi sejak target terakhir dimodifikasi, atau jika target tidak ada. Pelaksanaan pembaruan ini dapat terjadi secara bersamaan.

Sintaks berkas aturan adalah sebagai berikut.

target: [ prerequisites ... ]
 [TAB]  command1
 [TAB]  -command2 # ignore errors
 [TAB]  @command3 # suppress echoing

Di sini "[TAB]" adalah kode TAB. Setiap baris ditafsirkan oleh shell setelah membuat substitusi variabel. Gunakan "\" di akhir baris untuk melanjutkan skrip. Gunakan "$$" untuk memasukkan "$" bagi nilai lingkungan untuk skrip shell.

Aturan implisit untuk target dan prasyarat dapat ditulis, misalnya, dengan yang berikut.

%.o: %.c header.h

Di sini, target berisi karakter "%" (tepat satu dari mereka). "%" bisa cocok dengan sebarang sub string tidak kosong dalam nama berkas target yang sebenarnya. Prasyarat juga menggunakan "%" untuk menunjukkan bagaimana nama mereka berhubungan dengan nama target yang sebenarnya.



Jalankan "make -p -f/dev/null" untuk melihat aturan internal otomatis.

Autotools adalah keluarga alat pemrograman yang dirancang untuk membantu dalam membuat paket kode sumber portabel ke banyak sistem mirip Unix.

  • Autoconf adalah alat untuk menghasilkan skrip shell "configure" dari "configure.ac".

    • "configure" digunakan kemudian untuk menghasilkan "Makefile" dari templat "Makefile.in".

  • Automake adalah alat untuk menghasilkan"Makefile.in" dari "Makefile.am".

  • Libtool adalah skrip shell untuk mengatasi masalah portabilitas perangkat lunak saat menyusun pustaka bersama dari kode sumber.

Sistem build perangkat lunak telah berkembang:

  • Autotools di bagian atas Make telah menjadi standar de facto untuk infrastruktur bangunan portabel sejak 1990-an. Ini sangat lambat.

  • CMake initially released in 2000 improved speed significantly but was originally built on the top of inherently slow Make. (Now Ninja can be its backend.)

  • Ninja initially released in 2012 is meant to replace Make for the further improved build speed and is designed to have its input files generated by a higher-level build system.

  • Meson awalnya dirilis pada tahun 2013 adalah sistem build tingkat tinggi yang baru, populer, dan cepat yang menggunakan Ninja sebagai backend-nya.

Lihat dokumen yang ditemukan di "The Meson Build system" dan "The Ninja build system".

Halaman web dinamis interaktif dasar dapat dibuat sebagai berikut.

  • Kueri disajikan kepada pengguna peramban menggunakan formulir HTML.

  • Mengisi dan mengklik entri formulir mengirimkan salah satu string URL berikut dengan parameter yang dikodekan dari peramban ke server web.

    • "https://www.foo.dom/cgi-bin/program.pl?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3"

    • "https://www.foo.dom/cgi-bin/program.py?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3"

    • "https://www.foo.dom/program.php?VAR1=VAL1&VAR2=VAL2&VAR3=VAL3"

  • " %nn" dalam URL diganti dengan sebuah karakter dengan nilai heksadesimal nn.

  • Variabel lingkungan diatur sebagai: "QUERY_STRING="VAR1=VAL1 VAR2=VAL2 VAR3=VAL3"".

  • Program CGI (salah satu dari "program.*") di server web mengeksekusi dirinya sendiri dengan variabel lingkungan "$QUERY_STRING".

  • stdout program CGI dikirim ke peramban web dan disajikan sebagai halaman web dinamis interaktif.

Untuk alasan keamanan lebih baik tidak membuat hack baru untuk mengurai parameter CGI. Ada modul yang telah mapan untuk mereka di Perl dan Python. PHP hadir dengan fungsi-fungsi ini. Ketika penyimpanan data klien diperlukan, cookie HTTP digunakan. Ketika pemrosesan data sisi klien diperlukan, Javascript sering digunakan.

Untuk informasi lebih lanjut, lihat Common Gateway Interface, The Apache Software Foundation, dan JavaScript.

Mencari "tutorial CGI" di Google dengan mengetik URL yang dikodekan https://www.google.com/search?hl=en&ie=UTF-8&q=CGI+tutorial langsung ke alamat peramban adalah cara yang baik untuk melihat skrip CGI beraksi di server Google.

Jika Anda ingin membuat paket Debian, baca berikut ini.

Ada paket seperti debmake, dh-make, dh-make-perl, dll., yang membantu pengemasan.



[7] Some tweaks may be required to get them work under the current system.