Từ 1 tới 8 trên tổng số 8 kết quả

Đề tài: Sử dụng và lập trình trên GNU/Linux từ cơ bản đến nâng cao [Các thành viên congdongcviet biên soạn và sưu tầm]

  1. #1
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Thumbs down Sử dụng và lập trình trên GNU/Linux từ cơ bản đến nâng cao [Các thành viên congdongcviet biên soạn và sưu tầm]

    Mục lục của topic này :

    #1 - Những kiến thức căn bản về terminal ; về hệ thống file và thư mục trong ; một số lệnh thông dụng thao tác file và thư mục ; về BASH trong GNU/Linux. ( luc13aka47 )

    #2 và #3 - Tìm hiểu về trình biên soạn EMACS, trình biên dịch GCC ( GNU Compiler Collection )trình tự động biên dịch GNU Make trong GNU/Linux. ( luc13aka47 )

    Mọi người chia sẻ nào Mình sẽ cập nhật mục lục thường xuyên.

    Command line interface trong Linux


    The shell program

    Shell là chương trình tương tác giữa bạn và OS. Khi bạn gõ lệnh, shell đọc các lệnh đó từ bàn phím, xử lý chúng và gửi chúng tới OS. Có nhiều chương trình shell khác nhau, nhưng trên hầu hết Linux OS, bash (Bourne Again SHell) là mặc định.
    Nếu bạn đang sử dụng GUI, bạn muốn sử dụng CLI ( Command line interface ), có 2 cách, 1 là chuyển tới virtual terminal , 2 là khởi động terminal emulator.

    Terminal emulator

    Là chương trình tạo 1 cửa sổ và chạy shell trên nó. Nó giống như cmd trong Windows.
    Có nhiều termianl emulator, như : xterm, rxvt, gnome-terminal, konsole, kvt, eterm, …

    Virtual terminal

    Một cách khác để sử dụng CLI là rời khỏi GUI hoàn toàn. Ta có thể tắt GUI, nhưng có 1 cách khác, đó là chuyển tới virtual terminal khác. Theo mặc định, linux có 6 virutal terminal, và cái thứ 7 chạy GUI.
    Nhấn Ctrl + Alt + F1 để chuyển tới virtual terminal thứ nhất, Ctrl + Alt + F2 để chuyển tới cái thứ 2, … Thông thường, Ctrl + Alt + F7 sẽ đưa ta về GUI.

    The command prompt

    Thông thường, prompt gồm tên user và tên máy, theo sau là $, hoặc > ; nếu là # thì bạn đang sử dụng root.

    Wildcards

    Là 1 tính năng giống như regex, cho phép theo tác với pattern tùy chọn.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_10.png
Lần xem:	16
Size:		12.9 KB
ID:		10390

    Ví dụ.

    Xóa toàn bộ file trong thư mục đang là việc.
    $ rm *
    Di chuyển các file có pattern :
    $ mv *linux*.html dir1
    Đọc các file với pattern :
    $ less d*.txt
    Xóa các file với pattern:
    $ rm junk.???
    Liệt kê các file với pattern :
    $ ls hda[0-9]
    $ ls hda[0-9][0-9]
    Copy các file tới pattern :
    $ cp [A-Z]* dir2
    Remove các file với pattern :
    $ rm *[!cehg]

    Hệ thống tập tin và thư mục trên Linux

    Các thư mục và hệ thống tập tin ( mục này tham khảo quantrimang.com )

    Hệ thống tập tin của Linux và Unix được tổ chức theo một hệ thống phân bậc tương tự cấu trúc của một cây phân cấp. Bậc cao nhất của hệ thống tập tin là thư mục gốc, được ký hiệu bằng vạch chéo “/” (root directory). Đối với các hệ điều hành Unix và Linux tất các thiết bị kết nối vào máy tính đều được nhận dạng như các tập tin, kể cả những linh kiện như ổ đĩa cứng, các phân vùng đĩa cứng và các ổ USB. Điều này có nghĩa là tất cả các tập tin và thư mục đều nằm dưới thư mục gốc, ngay cả những tập tin biểu tượng cho các ổ đĩa cứng.

    Ví dụ, /home/nttvinh/nguyen/scnp.odt chỉ toàn bộ đường dẫn đến tập tin scnp.odt có trong thư mục nttvinh là thư mục phụ nằm trong thư mục home, ngay dưới thư mục gốc (/).

    Nằm dưới thư mục gốc (/) có một loạt các thư mục quan trọng của hệ thống tập tin được công nhận ở tất cả các bản phân phối Linux khác nhau. Sau đây là danh sách các thư mục thông thường được nhìn thấy dưới thư mục gốc (/) :

    • /bin – chứa các ứng dụng quan trọng (binary applications),
    • /boot – các tập tin cấu hình cho quá trình khởi động hệ thống (boot configuration files),
    • /dev – chứa các tập tin là chứng nhận cho các thiết bị của hệ thống (device files)
    • /etc – chứa các tập tin cấu hình của hệ thống, các tập tin lệnh để khởi động các dịch vụ của hệ thống...
    • /home – thư mục này chứa các thư mục cá nhân của những người có quyền truy cập vào hệ thống (local users' home directories),
    • /lib – thư mục này lưu các thư viện chia sẻ của hệ thống (system libraries)
    • /lost+found – thư mục này được dùng để lưu các tập tin không có thư mục mẹ mà được tìm thấy dưới thư mục gốc (/) sau khi thực hiện lệnh kiểm tra hệ thống tập tin (fsck).
    • /media – thư mục này được dùng để tạo ra các tập tin gắn (loaded) tạm thời được hệ thống tạo ra khi một thiết bị lưu động (removable media) được cắm vào như đĩa CDs, máy ảnh kỹ thuật số...
    • /mnt – thư mục này được dùng để gắn các hệ thống tập tin tạm thời (mounted filesystems),
    • /opt – thư mục dùng dể chứa các phần mềm ứng dụng (optional applications) đã được cài đặt thêm,
    • /proc – đây là một thư mục đặc biệt linh động để lưu các thông tin về tình trạng của hệ thống, đặc biệt về các tiến trình (processes) đang hoạt động,
    • /root – đây là thư mục nhà của người quản trị hệ thống (root),
    • /sbin – thư mục này lưu lại các tập tin thực thi của hệ thống (system binaries)
    • /sys – thư mục này lưu các tập tin của hệ thống (system files),
    • /tmp – thư mục này lưu lại các tập tin được tạo ra tạm thời (temporary files),
    • /usr – thư mục này lưu và chứa những tập tin của các ứng dụng chính đã được cài đặt cho mọi người dùng (all users),
    • /var – thư mục này lưu lại tập tin ghi các số liệu biến đổi (variable files) như các tập tin dữ liệu và tập tin bản ghi (logs and databases).

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1.jpg
Lần xem:	25
Size:		20.0 KB
ID:		10381

    Ổ đĩa và các Partition

    • /dev/hda Ổ đĩa cứng IDE đầu tiên (chính)
    • /dev/hdb Ổ đĩa cứng IDE thứ hai (thứ cấp)
    • /dev/sda Ổ đĩa cứng SCSI đầu tiên
    • /dev/sdb Ổ đĩa cứng SCSI thứ hai
    • /dev/fd0 Ổ đĩa mềm đầu tiên
    • /dev/fd1 Ổ đĩa mềm thứ hai

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_2.jpg
Lần xem:	9
Size:		22.5 KB
ID:		10382

    Ví dụ chúng ta chạy lệnh ls –l firstdoc.txt thấy kết quả như sau:
    -rwxrw-r-- 1 User1 Testers 512 Oct 24 19:42 firstdoc.txt
    Ý nghĩa của các field là:

    • File Access Permission: -rwxrw-r--
    • Số liên kết: 1
    • File Owner: User1
    • Group: Testers
    • File Size (bytes): 512
    • Lần hiệu chỉnh cuối: Oct 24
    • Last Modification Time: 19:42
    • File name: firstdoc.txt

    Ngoài ra, qua lệnh ls -i chúng ta sẽ biết được firstdoc.txt là tập tin hay thư mục dựa theo:

    • Nếu kí tự đầu tiên là (-), thì đây là tập tin.
    • Nếu kí tự đầu tiên là d, thì đối tượng là thư mục.
    • Nếu kí tự đầu tiên là l, thì đầy là một liên kết (symbolic link) trỏ đến một file khác (gần giống với shortcut trên Windows OS).
    • Nếu kí tự đầu tiên là b, đối tượng là block device ví dụ như disk drive.
    • Nếu kí tự đầu tiên là c, đối tượng là character device như serial port.

    Object Ownership

    Trong ví dụ trên chúng ta thấy các tập tin đều có một group owner và file owner. Trong trường hợp muốn thay đổi ownership cho group hay user khác hãy đăng nhập với quyền root và thự hiện lệnh sau để đổi quyền ownership đối với tập tin payroll.doc cho người dùng vp_finance
    chown vp_finance payroll.doc
    Nếu muốn đổi quyền ownership cho group accounting hãy thực hiện lệnh
    chown vp_finance.accounting payroll.doc
    Trong trường hợp muốn chuyển quyền ownership toàn bộ thư mục và các tập tin bên trong thì thự hiện lệnh chown với tùy chọn –R:
    chown -R vp_marketing.marketing /marketing/June
    chown -R .marketing /marketing/June

    Ngoài ra, nếu muốn chuyển quyền ownership mà không có quyền root thì có thể dùng lệnh chgrp nhưng lúc này bạn phải thuộc group có quyền ownership và group muốn chuyển quyền này.

    Một số lệnh thao tác với thư mục

    Câu lệnh pwd – Print working directory - Bạn đang ở đâu ?

    Câu lệnh này in ra địa chỉ tuyệt đối của thư mục mà ta đang làm việc.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3.png
Lần xem:	9
Size:		6.6 KB
ID:		10383

    Câu lệnh ls – Liệt kê nội dung của thư mục

    Câu lệnh này in ra các file hoặc thư mục mà trong thư mục bạn đang làm việc và 1 thư mục được chỉ định bởi đường dẫn.
    Có các tùy chọn thêm điều khiển cách liệt kê :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_4.png
Lần xem:	19
Size:		38.7 KB
ID:		10384

    Sử dụng tùy chọn –a để liệt kê cả các file và thư mục ẩn.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_5.png
Lần xem:	10
Size:		38.4 KB
ID:		10385

    Absolute pathnames – địa chỉ tuyệt đối

    Là địa chỉ bắt đầu từ thư mục root ( dấu gạch chéo / ).
    Ta có thể sử dụng địa chỉ tuyệt đối để truyền tham số tới ls, liệt kê nội dung trong 1 thư mục.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_6.png
Lần xem:	26
Size:		14.2 KB
ID:		10386

    Câu lệnh cd – Change directory – Thay đổi thư mục làm việc hiện tại

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_7.png
Lần xem:	7
Size:		8.0 KB
ID:		10387

    Relative pathnames – địa chỉ tương đối

    Là 2 dấu chấm ( .. ) hoặc địa chỉ có dấu . ở đầu.
    Miêu tả địa chỉ bắt đầu từ thư mục đang làm việc.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_8.png
Lần xem:	20
Size:		24.3 KB
ID:		10388

    Tạo thư mục

    Sử dụng lệnh mkdir.
    $ mkdir dir1

    Xóa thư mục

    Sử dụng lệnh rmdir với thư mục rỗng, sử dụng lệnh rm với tùy chọn -r (recursively ) với thư mục không rỗng.
    $ rmdir dir1
    $ rm -ir dir1

    Copy và move thư mục

    Sử dụng cp với tùy chọn -r để copy thư mục ( nếu không có tùy chọn -r , sẽ có lỗi ):
    $ cp -r dir1 dir2
    Nếu dir2 chưa tồn tại, nó sẽ được tạo trước khi sao chép dir1. Nếu dir2 đã tồn tại, dir1 sẽ được sao chép tới dir2.
    Sử dụng lệnh mv để move thư mục.
    mv dir1 dir2
    Nếu dir2 chưa tồn tại, dir1 sẽ được rename là dir2. Nếu dir2 đã tồn tại, dir1 sẽ được move tới dir2 dưới tên dir2/dir1.

    Một số lệnh thao tác file

    Câu lệnh file – Xác định kiểu của file

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_9.png
Lần xem:	19
Size:		21.0 KB
ID:		10389

    Câu lệnh cat và less - Đọc file dạng text

    Lệnh cat

    Đọc text file mà không phân trang.
    Topic173.2.png

    Lệnh less

    Đọc text file theo kiểu phân trang.
    Sử dụng giống cat.
    Ta cũng có thể đọc nhiều file cùng 1 lúc:
    $ less file1 file2 file3
    Các phím điều khiển khi đọc file với less :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_11.png
Lần xem:	32
Size:		20.3 KB
ID:		10391

    Thao tác copy, rename, move, remove file

    Lưu ý là Linux không có lệnh undo, bởi vậy hãy cẩn thận khi sử dụng các lệnh thao tác với file.

    Copy

    Sử dụng lệnh cp.
    $ cp file file2
    Nếu file2 không tồn tại, file2 sẽ được tạo, nếu file2 đã tồn tại, nó sẽ bị ghi đè.
    Ta có thể sử dụng tùy chọn -i để xác minh việc copy.
    $ cp -i file file2
    cp: overwrite `file2'? n
    $
    Copy file tới 1 thư mục :
    $ cp file dir1
    Copy file tới 1 thư mục với tên khác :
    $ cp file dir1/file2
    Copy nhiều file tới 1 thư mục :
    $ cp file1 file2 file3 dir1

    Move và rename

    Sử dụng lệnh mv.
    $ mv file file2
    Nếu file2 chưa tồn tại, file2 sẽ được tạo, nếu file2 đã tồn tại, nó sẽ bị ghi đè.
    Nên sử dụng tùy chọn -i để xác minh.
    Move file tới thư mục khác :
    $ mv file dir1
    Move file tới thư mục khác với tên khác :
    $ mv file dir1/file2

    Remove

    Sử dụng lệnh rm.
    $ rm -i file
    Có thể remove nhiều file cùng lúc :
    rm file1 file2

    Tìm hiểu Bash trong Linux (mục này tham khảo quantrimang.com )

    Đó là giao diện lệnh mặc định trên hầu hết những bản phân phối GNU/Linux mới. Bash là giao diện lệnh chính của hệ điều hành Linux, nó nhận, thông dịch và thực thi lệnh, sau đó cung cấp bộ nhớ điều khiển giao diện và thực thi những tác vụ được tự động hóa.

    Bash ẩn đi nhiều công cụ mạnh và phím tắt. Nếu thường xuyên làm việc với dòng lệnh, công cụ này có thể giúp bạn tiết kiệm được khá nhiều thời gian. Dưới đây là 10 tính năng hữu dụng nhất của Bash.

    1. Dễ gọi lại lệnh

    Bash theo dõi mọi lệnh thực thi trong một bộ đệm lược sử, và cho phép người dùng gọi lại những lệnh trước đó bằng cách dùng phím Up (lên) và Down (xuống) để lựa chọn. Thậm chí người dùng có thể gọi lại lệnh thực thi trước đó nhanh hơn nữa bằng cách nhập một vài kí tự đầu tiên của lệnh sau đó nhấn tổ hợp phím Ctrl+R, sau đó bash sẽ kiểm tra lược sử lệnh để tìm ra những lệnh phù hợp nhất với điều kiện tìm và hiển thị chúng trên giao diện console. Nhấn tiếp tổ hợp phím Ctrl+R để xem danh sách lệnh phù hợp tiếp theo.

    2. Sử dụng bí danh lệnh

    Nếu thường xuyên chạy một lệnh trên cùng một nhóm tùy chọn, bạn có thể sử dụng bash để tạo một bí danh cho lệnh này. Bí danh này sẽ bao gồm những tùy chọn được yêu cầu, vì vậy bạn sẽ không cần phải ghi nhớ chúng hay đặt lại những tùy chọn này mỗi khi chạy lại nó. Ví dụ, nếu thường xuyên sử dụng lệnh ls với tùy chọn -l để xem một danh sách thư mục chi tiết, bạn có thể sử dụng lệnh bash> alias ls='ls -l' để tạo một bí danh tự động tích hợp tùy chọn -l.

    Khi bí danh này đã được tạo, nhập ls vào dấu nhắc lệnh, bash sẽ gọi bí danh này và kết xuất kết quả -l của lệnh ls. Bạn có thể xem danh sách bí danh hiện có bằng cách dùng lệnh alias (không có đối số), và xóa một bí danh với lệnh unalias.

    3. Sử dụng Filename Auto-Completion

    Bash hỗ trợ Filename Auto-Completion tại thông báo lệnh. Để sử dụng tính năng này, nhập những chữ cái đầu tiên trong tên file, sau đó tab.bash sẽ kiểm tra thư mục hiện thời, cũng như mọi thư mục khác trong Search Path (đường dẫn tìm kiếm), để tìm ra file có tên phù hợp nhất với điều kiện tìm. Nếu tìm thấy nhiều kết quả, bạn sẽ được nhắc nhở lựa chọn ra một kết quả.

    4. Hiệu chỉnh dòng lệnh bằng phím tắt

    Bash hỗ trợ nhiều phím tắt để điều khiển và hiệu chỉnh dòng lệnh. Ví dụ:

    • Tổ hợp phím Ctrl+A di chuyển con trỏ lên đầu dòng lệnh.


    • Tổ hợp phím Ctrl+E di chuyển con trỏ đến cuối dòng lệnh.


    • Tổ hợp phím Ctrl+W xóa từ đứng trước con trỏ.


    • Tổ hợp phím Ctrl+K xóa mọi kí tự sau con trỏ.


    • Tổ hợp phím Ctrl+Y khôi phục xóa.

    5. Tự động thông báo thư mới

    Người dùng có thê cấu hình bash tự đông thông báo khi có thư đến bằng cách cài đặt biến số $MAILPATH chỉ vào mail spool cục bộ. Ví dụ, lệnh bash> MAILPATH='/var/spool/mail/user' bash> export MAILPATH Causes bash sẽ đưa ra thông báo trên giao diện console của user mỗi khi mail spool của user có một tin nhắn mới.

    6. Chạy tác vụ trong Background

    Bash cho phép người dùng chạy một hay nhiều tác vụ trong một background, và lựa chọn hoãn hay chạy lại một tác vụ hiện thời bất kì. Để chạy một tác vụ trong background, chỉ cần thêm một ký tự “&” vào cuối dòng lệnh. Ví dụ:
    bash> tail -f /var/log/messages &
    Mỗi tác vụ chạy trên background theo phương pháp này sẽ được gán một ID ược in ra giao diện console. Một tác vụ có thể được đưa trở lại foreground bằng lệnh fg jobnumber, trong đó jobnumber là ID của tác vụ bạn muốn đưa lên foreground. Ví dụ:
    bash> fg 1
    Bạn có thể xem danh sách tác vụ đang thực hiện bằng cách nhập lệnh jobs vào dấu nhắc lệnh trong bash.

    7. Truy cập nhanh vào thư mục thường sử dụng

    Có thể bạn đã biết biến số $PATH trong Search Path của bash, Search Path là những thư mục được tìm kiếm tiếp theo sau khi đã tìm kiếm trong thư mục hiện thời. Tuy nhiên bash cũng hỗ trợ biến số $CDPATH liệt kê những thư mục mà lệnh cd sẽ truy lục khi cố gắng thay đổi thư mục. Để sử dụng tính năng này, trước tiên cần phải gán biến số $CDPATH cho một danh sách thư mục. Ví dụ:
    bash> CDPATH='.:~:/usr/local/apache/htdocs:/disk1/backups'
    bash> export CDPATH
    Từ giờ, bất cứ khi nào lệnh cd được sử dụng, bash sẽ kiểm tra mọi thư mục trong danh sách $CDPATH để tìm ra những thư mục có tên phù hợp nhất.

    8. Thực hiện tính toán

    Bash có thể thực hiện một số phép tính đơn giản trong môi trường lệnh. Để sử dụng tính năng này, người dùng chỉ cần nhập biểu thức toán học cần thực hiện vào dấu nhắc lệnh bên trong hai ngoặc đơn, sau đó bash sẽ tính toán và phản hồi kết quả. Ví dụ, khi nhập lệnh bash> echo $((16/2)), bash sẽ trả về kết quả là 8.

    9. Tùy chỉnh thông báo trên giao diện

    Người dùng cũng có thể tùy chỉnh lời nhắc trong thông báo lệnh của bash để hiển thị tên người dùng, tên máy chủ, thời gian hiện tại, mức trung bình tải và/hoặc thư mục hiện đang làm việc.

    Để hiển thị những thông tin này, người dùng phải thay đổi biến số $PS1 như sau:
    bash> PS1='\u@\h:\w \@> '
    bash> export PS1 root@medusa:/tmp 03:01 PM>
    Sau đó tên của người dùng đang đăng nhập, tên máy chủ, thư mục hiện đang làm việc và thời gian hiện tại sẽ được hiển thị trên lời nhắc trong giao diện bash. Bạn cũng có thể xem danh sách kí hiệu của bash trong trang hướng dẫn.

    10. Hướng dẫn sử dụng lệnh

    Bash còn có tính năng trợ giúp sử dụng tất cả các lệnh tích hợp trên nó. Bạn chỉ cần nhập help vào dấu nhắc lệnh để xem danh sách tất cả các lệnh tích hợp trên bash. Để xem trợ giúp cho mỗi lệnh, nhập lệnh help command, trong đó command là lệnh bạn muốn được trợ giúp. Ví dụ:
    bash> help alias
    ...some help text...
    Do đó, bạn có thể xem chi tiết trợ giúp trên giao diện bash bằng cách nhập man bash vào dấu nhắc lệnh.
    Đã được chỉnh sửa lần cuối bởi luc13aka47 : 02-11-2012 lúc 11:14 AM.

  2. #2
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Tìm hiểu trình biên soạn GNU Emacs

    GNU Emacs có thể nói là 1 trình biên soạn thông dụng nhất và nhiều tính năng có sẵn trên Linux.

    Emacs không hẳn là 1 trình biên soạn, ta có thể gửi mail , duyệt web với Emacs, … có thể tùy chỉnh và mở rộng nó theo rất nhiều cách, …

    Để vào GNU Emacs, gõ ( trên Backtrack 5 R2 ):

    Code:
    emacs23
    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_1.png
Lần xem:	60
Size:		310.1 KB
ID:		10392

    Để một file mã nguồn mới, vào File => Visit New File :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_2.png
Lần xem:	34
Size:		264.9 KB
ID:		10393

    Nếu muốn tạo 1 file mã nguồn C, sử dụng tên với đuôi *.c hoặc *.h, nếu muốn tạo 1 file mã nguồn C++, sử dụng tên với đuôi *.cpp, *hpp, *.cxx, *.hxx, *.C hoặc *.H. Như ảnh minh họa trên, đang tạo 1 file mã nguồn C++ có tên Nhom22_DHKTPM2.cpp.

    Emacs có thể mở cùng 1 lúc nhiều file, danh sách các file nằm trong Buffers :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_3.png
Lần xem:	28
Size:		271.3 KB
ID:		10394

    Muốn đóng file hiện đang làm việc, click vào nút X trên toolbar, hoặc vào File => Close.

    Emacs còn có tính năng hỗ trợ nổi bật cú pháp của nhiều ngôn ngữ lập trình.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_4.png
Lần xem:	33
Size:		270.5 KB
ID:		10395

    Biên dịch với GCC

    GCC là viết tắt của GNU Compiler Collection, là tập hợp các trình biên dịch cho các ngôn ngữ C, C++, Java, Objective-C, Fortran, Chill ; là 1 phần của hệ điều hành GNU/Linux.

    Tên của trình biên dịch ngôn ngữ C là gcc, để biên dịch 1 file mã nguồn C, sử dụng tùy chọn -c , ví dụ :

    Code:
    gcc -c main.c
    Trình biên dịch gcc sẽ cho ra 1 object file main.o.

    Tên của trình biên dịch ngôn ngữ C++ là g++, cũng tương tự, để biên dịch 1 file mã ngồn C++, sử dụng tùy chọn -c, ví dụ :

    Code:
    g++ -c main.cpp
    Tùy chọn -c nói cho trình biên dịch biết chỉ cần biên dịch mã nguồn thành object file ; nếu không có tùy chọn này, trình biên dịch sẽ cho ra 1 file thực thi.

    Ngoài ra, có nhiều tùy chọn hữu dụng khác :

    -I, nói cho trình biên dịch biết cần tìm các header file ở đâu. Theo mặc định, trình biên dịch tìm các header file tại thư mục của file mã nguồn và trong thư mục chứa các header file của thư viện chuẩn.

    Ví dụ, tại thư mục hiện tại, ta có file mã nguồn main.cpp, và các header file cần thiết cho việc biên dịch nằm trong thư mục ./include, thì cú pháp sẽ là :

    Code:
    g++ -c -I ../include main.cpp
    -D, nói cho trình biên dịch biết cần khai báo 1 macro nào đó. Ví dụ, ta muốn khai báo macro NDEBUG để bỏ qua 1 đơn vị mã nguồn nào đó chỉ phục vụ cho việc debug trong file mã nguồn main.cpp ( tất nhiên ta có thể thêm #define NDEBUG ngay trong file main.cpp, nhưng như thế sẽ bất tiện khi ta lại muốn debug ) , cú pháp sẽ là :

    Code:
    g++ -c -D NDEBUG main.cpp
    Nếu muốn macro NDEBUG có 1 giá trị cụ thể nào đó, ta sử dụng cú pháp :

    Code:
    g++ -c -D NDEBU=3 main.cpp
    Nếu muốn biên dịch với chế độ tối ưu, giúp chương trình chạy tốt hơn, ta có thể sử dụng tùy chọn -02 ( GCC có 1 vài mức tối ưu, trong đó mức thứ 2 ( -02 ) là thích hợp cho hầu hết các chương trình ), sử dụng cú pháp :

    Code:
    g++ -c -02 main.cpp
    Chú ý rằng, biên dịch với chế độ tối ưu sẽ khiến chương trình khó debug hơn.

    Để có được danh sách tất cả các tùy chọn biên dịch của GCC, sử dụng cú pháp :

    Code:
    info gcc
    Ví dụ :

    Có 1 C++ header file NghichDao.hpp :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_5.png
Lần xem:	96
Size:		96.0 KB
ID:		10396

    1 C++ source code file NghichDao.cpp :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_6.png
Lần xem:	52
Size:		97.1 KB
ID:		10397

    1 C++ source code file Nhom22_DHKTPM2.cpp :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_7.png
Lần xem:	50
Size:		107.1 KB
ID:		10398

    Biên dịch các file trên :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_8.png
Lần xem:	109
Size:		860.1 KB
ID:		10399

    Lý do sử dụng tùy chọn -c là vì các file mã nguồn có liên kết với nhau ( Nhom22_DHKTPM2.cpp có #include “NghichDao.hpp” ) , nếu biên dịch ngay ra file thực thi trước khi liên kết các object file, chương trình không chạy được.

    Liên kết object file

    Như ở trên đã nói tới việc lên kết các object file, để liên kết các object file , ta sử dụng tùy chọn -o.

    Nên luôn sử dụng g++ để liên kết các chương trình có chứa mã C++, ngay cả khi nó cũng chứa mã C. Nếu chương trình chỉ chứa mã C, thì nên sử dụng gcc.

    Như ví dụ ở phần trên, để liên kết object file Nhom22_DHKTPM2.o và NghichDao.o, sử dụng cú pháp :

    Code:
    g++ -o TenFileThucThi Nhom22_KTPM2.o NghichDao.o
    g++ tự động liên kết mã nguồn với các thư viện runtime cần thiết, ví dụ như thư viện iostream, để sử dụng các đối tượng I/O cout và cin ; hay <cassert> để sử dụng assert.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_9.png
Lần xem:	44
Size:		384.8 KB
ID:		10400

    Nếu ta cần liên kết với 1 thư viện khác ( ví dụ như thư viện giao diện đồ họa người dùng ) , ta cần sử dụng tùy chọn -l. Trong Linux, hầu hết tên thư viện đều bắt đầu với “lib”, ví dụ thư viện Pluggable Authentication Module (PAM) có tên libpam.a, để liên kết với thư viện libpam.a, sử dụng cú pháp :

    Code:
    g++ -o TenFileThucThi Nhom22_KTPM2K5.o NghichDao.o -lpam
    Trình biên dịch sẽ tự thêm “lib” và “.a”.

    Như các header file, trình biên dịch tìm các thư viện tại những thư mục chuẩn, như thư mục /lib và /usr/lib chứa các thư viện hệ thống chuẩn. Nếu muốn liên kết với các thư viện khác, cần sử dụng tùy chọn -L để chỉ cho trình biên dịch biết thư mục chứa thư viện cần liên kết ở đâu.

    Ví dụ :

    Code:
    g++ -o TenFileThucThi Nhom22_KTPM2K5.o NghichDao.o -L/user/local/lib/pam -lpam
    Mặc dù ta không phải sử dụng tùy chọn -I để chỉ cho trình biên dịch tìm kiếm header file tại thư mục đang làm việc, nhưng ta phải sử dụng -L để chỉ cho trình biên dịch tìm kiếm thư viện kể cả tại thư mục đang làm việc. Ví dụ :

    Code:
    % gcc -o app app.o -L. -ltest


    Tự động biên dịch lại chương trình với GNU Make


    Trong ví dụ trên, ta đã biên dịch từng file mã nguồn, sau đó liên kết các object file để có được 1 chương trình thực thi. Vấn đề là, khi ta thay đổi mã nguồn, ta cùng cần phải biên dịch lại chúng để có được object file mới, sau đó lại liên kết các object file mới đó để có được file thực thi thay đổi như mong muốn. Điều này rất bất tiện. Có 1 cách nhẹ nhàng hơn, đó là sử dụng GNU Make.

    Ý tưởng đằng sau Make rất đơn giản. Ta nói cho make “target” là gì, sau đó đưa “rules” để giải thích làm gì với “target”, ta cũng có thể chỉ định “dependencies” như những tùy chọn thêm khi nói “target”.

    Để tạo 1 make, ta tạo 1 file có tên Makefile có nội dung :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_10.png
Lần xem:	99
Size:		111.3 KB
ID:		10401

    Gõ make để thực thi :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_1_11.png
Lần xem:	67
Size:		837.1 KB
ID:		10402

  3. #3
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Cấu trúc của 1 GNU Make gồm các bộ :

    Code:
    target : dependencies
    	rules
    - target là mục tiêu cần đạt được trong 1 quá trình, ví dụ, target là FileThucThi như trong ví dụ trên.
    - dependencies là những gì cần để đạt được target, như ví dụ trên, cần biên dịch được FileThucThi cần 2 object file : Nhom22_DHKTPM2.o và NghichDao.o.
    - rules là cách để đạt được target, rules phải bắt đầu với 1 khoảng trống bằng 1 “tab”, đó là quy định của GNU Make, như trong ví dụ trên , rules là :

    Code:
    	g++ $(CFLAGS) -o Nhom22_DHKTPM2.o NghichDao.o
    $(CFLAGS) là 1 biến make, ta có thể khai báo biến này khi gọi make trên terminal.

    Để thực thi makefile, duyệt terminal tới thư mục chứa makefile, gõ :

    Code:
    make
    terminal sẽ hiển thị như hình dưới :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_2_1.png
Lần xem:	55
Size:		824.9 KB
ID:		10403

    Ta cũng có thể chỉ định target cụ thể, khi đó make chỉ thực thi rules để tạo ra target chỉ định.

    Ví dụ. Chỉ định target là Clean. Khi đó chỉ có rules :

    Code:
    rm -f *.o FileThucThi
    là được thực thi.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_2_2.png
Lần xem:	31
Size:		735.6 KB
ID:		10404

    Để khai báo biến CFLAGS :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_2_3.png
Lần xem:	39
Size:		750.9 KB
ID:		10405

    Trong hình minh họa trên, ta khai báo CFLAGS = -g ; khi đó “-g” sẽ được đưua vào rules tại vị trí của $(CFLAGS). Tùy chọn -g để nói cho trình biên dịch lưu thông tin debug khi biên dịch.

  4. #4
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Trên là nội dung tài liệu mình viết và soạn cho bản thân và 1 phần là nộp báo cáo bài tập lớn hàng tuần cho thầy dạy Nhập môn công nghệ phần mềm ở trường

    Mọi người trong diễn đàn ai có cái gì liên quan tới Linux văng hết vào thảo luận nào, chấp nhận mọi thể loại gạch đá, văng càng loạn càng vui , ẹ ẹ

  5. #5
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Debug với GNU Debugger ( GDB )

    GDB là trình debug rất được ưa chuộng bởi các lập trình viên trên Linux.

    Biên dịch với thông tin debug

    Như trong ví dụ sử dụng biến make ở trên, để lưu thông tin debug khi biên dịch, ta sử dụng tùy chọn -g.

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3_1.png
Lần xem:	31
Size:		750.9 KB
ID:		10457

    Trình debug sử dụng thông tin debug để tính toán 1 địa chỉ nào đó là tương ứng với dòng nào trong file mã nguồn nào, hoặc làm thế nào để in ra biến cục bộ, ...

    Tìm nhiều thông tin hơn

    Tra cứu với Man pages

    Man pages viết tắt của manual pages - Trang hướng dẫn sử dụng.

    Man pages là nơi ta nên tìm kiếm đầu tiên khi muôn tra cứu thông tin về 1 lệnh hay 1 hàm nào đó.

    Các phiên bản phân phối của Linux chứa các man page cho hầu hết các câu lệnh, system calls và hàm thư viện chuẩn. Man pages được chia thành nhiều phần, với lập trình viên, các phần sau đáng quan tâm :

    (1) User commands
    (2) System calls
    (3) Standard library functions
    (8) System/administrative commands

    Các số là chỉ số phần.

    Sử dụng câu lệnh man để truy cập man page theo cú pháp :

    Code:
    man name
    Trong đó name là tên câu lệnh hoặc tên hàm.

    Đôi khi, 1 tên hàm hay 1 tên lệnh sẽ cho ra man page với nhiều hơn 1 phần, để chỉ định phần cần tra cứu, sử dụng cú pháp :

    Code:
    man n name
    n là chỉ số phần cần tra cứu.

    Ví dụ :

    Code:
    man 3 sleep
    Tra cứu phần 3 trong man page của hàm sleep() :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3_2.png
Lần xem:	23
Size:		774.4 KB
ID:		10458

    Ta có thể sử dụng câu lệnh whatis với cú pháp :

    Code:
    whatis name
    Để liệt kê tất cả các man page của lệnh hoặc hàm có tên name.

    Ví dụ :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3_3.png
Lần xem:	9
Size:		748.0 KB
ID:		10453

    Nếu không chắc chắn hoặc chưa biết lệnh hoặc hàm nào mà ta cần, ta có thể sử dụng cú pháp sau để tìm kiếm :

    Code:
    man -k keyword
    keyword là từ khóa có liên quan tới lệnh hoặc hàm cần tìm.

    Ví dụ : Tìm các hàm/ lệnh có liên quan với từ khóa “remove” :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3_4.png
Lần xem:	9
Size:		825.2 KB
ID:		10454

    Tra cứu với Info

    Hệ thống tài liệu info chứa nhiều tài liệu chi tiết về nhiều thành phần cốt lõi của hệ thống GNU/Linux, ngoài ra còn có thêm nhiều tài liệu về nhiều chương trình khác.

    Info pages là hypertext documents, tương tự như Web pages. Để truy cập sử dụng lệnh info trên terminal.

    Ví dụ, ta muốn tra cứu về libc, thư viện C của GNU, chứa nhiều system call, sử dụng cú pháp :

    Code:
    info libc
    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3_5.png
Lần xem:	10
Size:		785.7 KB
ID:		10455

    Tra cứu trong header files

    Ta có thể tìm hiểu được rất nhiều điều về các hàm hệ thống và cách sử dụng chúng bằng cách tìm hiểu header files.
    Các header file chuẩn nằm trong /usr/include và /usr/include/sys.

    Tra cứu trong source code

    GNU/Linux và các thành phần của nó hầu hết là mã nguồn mở. Bởi vậy, ta có thể nghiên cứu mã nguồn để tìm hiểu những gì ta cần.

    Tương tác với môi trường thực thi

    Có nhiều cách giúp chương trình giao tiếp với hệ điều hành và người dùng, như qua danh sách đối số ( ví dụ : được cung cấp bởi 2 tham số argc và argv của hàm main trong C/C++ ), qua thư viện chuẩn I/O của C là stdin và stdout, qua đối tượng chuẩn I/O của C++ là cout và cin, GNU/Linux cũng cung cấp nhiều cách khác để giúp chương trình giao tiếp với môi trường thực thi.

    Danh sách đối số dòng lệnh

    Một chương trình minh họa việc sử dụng danh sách đối số dòng lệnh :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_3_6.png
Lần xem:	41
Size:		100.7 KB
ID:		10456

    Quy ước Command-line của GNU/Linux

    Hầu hết các chương trình trong GNU/Linux đều tuần theo quy ước về cách các đối số được nhập vào.
    Các đối số được chia làm 2 loại :

    • Tùy chọn ( hoặc flags ).
    • Các đối số khác.

    Tùy chọn thay đổi cách chương trình thực thi.
    Các đối số khác thường cung cấp input hoặc output vào đâu.
    Các tùy chọn có 2 hình thức :

    • Tùy chọn rút gọn : Bắt đầu với 1 dấu gạch ngang ( - ) và sau đó là 1 kí tự ( thường là kí tự thường hoặc hoa ). Tùy chọn này giúp gõ nhanh chóng hơn.
    • Tùy chọn đầy đủ : Bắt đầu với 2 dấu gạch ngang ( -- ) và sau đó là tên tùy chọn ( có thể gồm chữ thường, hoa và gạch ngang ). Tùy chọn đầy đủ giúp dễ nhớ và dễ đọc.

    Theo GNU Coding Standards - 4.7 Standards for Command Line Interfaces, mỗi chương trình nên có 2 tùy chọn --version và --help. ( tại : http://www.gnu.org/prep/standards/html_node/index.html )

    Sử dụng các hàm phân tích danh sách đối số command-line

    Để hỗ trợ các mã nguồn C/C++ trong việc xử lý các tùy chọn trong danh sách đối số dòng lệnh, GNU/Linux cung cấp các hàm getopt(), getopt_long(), getopt_long_only(), để sử dụng, cần khai báo <getopt.h> với getopt_long() và getopt_long_only() ; <unistd.h> với getopt().

    C++ Code:
    1.        #include <unistd.h>
    2.    
    3.          int getopt(int argc, char * const argv[],
    4.                     const char *optstring);
    5.    
    6.          extern char *optarg;
    7.          extern int optind, opterr, optopt;
    8.    
    9.          #include <getopt.h>
    10.    
    11.          int getopt_long(int argc, char * const argv[],
    12.                     const char *optstring,
    13.                     const struct option *longopts, int *longindex);
    14.    
    15.          int getopt_long_only(int argc, char * const argv[],
    16.                     const char *optstring,
    17.                     const struct option *longopts, int *longindex);

    Hàm getopt()

    Hàm getopt() có nhiệm vụ phân tích cú pháp các đối số command-line.

    2 tham số của getopt() là argc và argv, tương ứng là số và mảng các đối số được nhập vào hàm main() khi chương trình được gọi.

    Một phần tử của argv bắt đầu với '-' ( không chính xác là '-' hay '--' ) được gọi là 1 option element.
    Kí tự của 1 option element ( bắt đầu từ bên phải '-' ) là những option character.

    Nếu getopt() được gọi lặp, nó sẽ return những option character từ những option element.
    Biến optind là chỉ số của element tiếp theo sẽ được xử lý trong argv.

    Hệ thống khởi tạo biến này với giá trị 1. Caller có thể reset nó tới 1.

    Nếu getopt() tìm thấy 1 option character nào khác, nó sẽ return character đó và update optind và biến static nextchar.

    Nếu getopt() không tìm thấy option character nào nữa, nó return -1. optind là chỉ số của phần tử đầu tiên trong argv mà không phải là 1 option.

    Tham số optstring của getopt() là 1 string chứa các option character hợp lệ. Nếu 1 character như vậy được theo sau bởi 1 dấu 2 chấm, option đó yêu cầu 1 đối số, vậy nên getopt() sẽ dùng optarg để trỏ tới text của đối số đó. 2 dấu 2 chấm nghĩa là option đó yêu cầu nhận 0 hoặc 1 đối số, vậy nên optarg sẽ trỏ tới đối số đó hoặc bằng 0 nếu không có đối số nào.

    Theo mặc định, getopt() sẽ thay đổi các phần tử trong argv khi nó scan. Vậy nên khi scan xong, tất cả các non-option sẽ ở cuối mảng.

    Có 2 chế độ khác nữa:

    • Nếu kí tự đầu tiên trong optstring là '+' hoặc biến môi trường POSIXLY_CORRECT được set, thì việc xử lý các option sẽ dừng ngay khi gặp 1 đối số non-option.
    • Nếu kí tự đầu tiên trong optstring là '-', thì mỗi element non-option trpng argv sẽ được xử lý như là 1 đối số của 1 option với character code 1.

    Nếu getopt() tìm thấy 1 option character không hợp lệ, nó sẽ in 1 thông báo lỗi tới stderr, lưu kí tự đó tới optopt và return '?'. Caller có thể chặn thông báo lỗi bằng việc set opterr = 0.

    Hàm getopt_long()

    Hàm này cũng tương tự như getopt(), ngoại trừ , nó cũng nhận long options, nhưng chúng phải bắt đầu với 2 dấu gạch ngang “--“.

    Long options có thể nhận tham số, theo cú pháp --arg=param hoặc --arg param.

    Tham số longopts của getopt_long() là con trỏ trỏ tới phần tử đầu tiên của mảng các struct option, được khai báo trong <getopt.h>.

    C++ Code:
    1. struct option {
    2.                const char *name;
    3.                int         has_arg;
    4.                int        *flag;
    5.                int         val;
    6.            };
    • name : Tên long option.
    • has_arg : Có giá trị :
      • no_argument ( hoặc 0 ) , nếu option không yêu cầu đối số đi kèm.
      • required_argument ( hoặc 1 ), nếu option yêu cầu 1 đối số đi kèm.
      • optional_argument ( hoặc 2 ), nếu option yêu cầu 1 đối số tùy chọn ( tức là có hoặc không cũng được ).


    • flag : Chỉ định giá trị return của hàm getopt_long() khi gặp long option. Nếu flag là NULL, getopt_long() sẽ return val, ngược lại getopt_long(0 sẽ return 0 nếu flag trỏ tới 1 biến, biến đó sẽ được gán với giá trị val nếu getopt_long() gặp option này, nếu không gặp thì không gán.
    • val : là giá trị return hoặc là giá trị sẽ được gán vào biến mà flag trỏ tới.

    Phần tử cuối cùng của mảng nên có 1 struct option với tất cả các trường bằng 0.

    Tham số longindex của getopt_long() nếu khác NULL, nó sẽ phải trỏ tới 1 biến, mà khi người dùng nhập 1 long option, getopt_long() sẽ gán biến đó với giá trị là index của option tương ứng trong mảng các struct option được trỏ bởi tham số longopts.

    Ví dụ. Chương trình minh họa cách sử dụng getopt_long().

    C++ Code:
    1.  #include <iostream>
    2.   #include <getopt.h> // for getopt_long()
    3.   #include <stdlib.h> // for exit()
    4.    
    5.   // biến lưu tên file thực thi
    6.   const char* TenChuongTrinh = NULL;
    7.    
    8.   // hàm hiển thị hướng dẫn sử dụng
    9.   void print_usage(std::ostream& out, int exit_code)
    10.   {
    11.     using namespace std;
    12.     out << "Su dung : " << TenChuongTrinh << " TuyChon [ inputfile ... ]" << endl;
    13.     out << "-h --help           Hien thi huong dan su dung." << endl;
    14.     out << "-o --output         Viet output toi file" << endl;
    15.     out << "-v --verbose        In danh sach cac doi so   ." << endl;
    16.    
    17.     exit(exit_code);
    18.   }
    19.    
    20.   int main(int argc, char** argv)
    21.   {
    22.     // biến lưu index của option tiếp theo
    23.     unsigned int next_option = 0;
    24.     // chuỗi các short option hợp lệ
    25.     const char* const short_option = "ho:v";
    26.     // mảng các struct option
    27.     const option long_option[] = {
    28.       {"help", 0, NULL, 'h'},
    29.       {"output", 1, NULL, 'o'},
    30.       {"verbose", 0, NULL, 'v'},
    31.       {NULL, 0, NULL, 0}};
    32.     // biến lưu đối số của --output hoặc -o
    33.     const char* output_filename = NULL;
    34.     // có hiển thị các đối số non-option
    35.     bool verbose = false;
    36.    
    37.     TenChuongTrinh = argv[0];
    38.    
    39.     do
    40.       {
    41.         // lấy option
    42.         next_option = getopt_long(argc, argv, short_option, long_option, &cur_option );
    43.    
    44.       switch(next_option)
    45.       {
    46.       case 'h':
    47.         print_usage(std::cout, 0);
    48.         break;
    49.       case 'o':
    50.         output_filename = optarg;
    51.         std::cout << "output_filename = " << output_filename << std::endl;
    52.         break;
    53.       case 'v':
    54.         verbose = true;
    55.         break;
    56.       case '?':
    57.         print_usage(std::cerr, 1);
    58.         break;
    59.       default: // -1
    60.         break;
    61.       }
    62.       }
    63.     while(next_option != -1 );
    64.    
    65.     if(verbose)
    66.       {
    67.         std::cout << "Cac doi so khong phai la option :" << std::endl;
    68.         for(unsigned int i = optind; i < argc ; i ++)
    69.       std::cout << argv[i] << std::endl;
    70.       }
    71.    
    72.    
    73.     return 0;
    74.   }
    Đã được chỉnh sửa lần cuối bởi luc13aka47 : 02-11-2012 lúc 11:13 AM.

  6. #6
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Mặc định Sử dụng và lập trình trên GNU/Linux từ cơ bản đến nâng cao [Các thành viên congdongcviet biên soạn và sưu tầm]

    Những vấn đề với khoảng trống và kí tự đặc biệt trong tên file

    Không có điều gì ngăn chúng ta sử dụng khoảng trống và kí tự đặc biệt trong tên file, nhưng khi sử dụng chúng, sẽ phát sinh 1 số vấn đề.

    Ví dụ, khi ta có 1 file tên : File with space.txt , và ta muốn đọc nội dung file đó với lệnh cat :

    Code:
    cat File with space.txt
    Khi đó, cat sẽ hiểu là ta muốn đọc 3 file tên : File, with và space.txt chứ không phải 1 file với tên File with space.txt.

    Một ví dụ nữa, khi ta có 1 file tên : File*.txt, và ta muốn xóa nó với lệnh rm :

    Code:
    rm File*.txt
    Có điều, * là 1 kí diện wildcard, đại diện cho 0 hoặc nhiều kí tự, khi đó rm sẽ hiểu là ta muốn xóa tất cả các file với tên bắt đầu bằng “File” và kết thúc là “.txt”, ví dụ như File.txt, File2.txt, đều bị xóa. Khi đó ta sẽ gắp vấn đề lớn nếu các file đó quan trọng.

    Có 2 cách đơn giản để ta có thể giải quyết những vấn đề trên :

    Cách 1 : Trích dẫn.

    Để đọc file với tên : File with space.txt, ta gõ lệnh :

    Code:
    cat ‘File with space.txt’
    Như trên, ta đã sử dụng trích dẫn với các dấu ‘’, để giải thích cho cat hiểu rằng ta muốn đọc 1 file tên : File with space.txt

    Để xóa file với tên : File*.txt, ta gõ lệnh :

    Code:
    rm ‘File*.txt’
    Khi đó, rm sẽ hiểu rằng ta muốn xóa 1 file tên : File*.txt.

    Cách 2 : Escaping.

    Để đọc file với tên : File with space.txt, ta gõ lệnh :

    Code:
    cat File\ with\ space.txt
    Bằng cách, đặt dấu \ trước mỗi khoảng cách hoặc kí tự đặc biệt, ta sẽ giải thích cho cat hiểu rằng đây là 1 tên file, chứ không phải nhiều file.

    Tương tự, để xóa file với tên : File*.txt, ta gõ lệnh :

    Code:
    cat File\*.txt
    Muốn đọc nội dung tất cả các file với tên bắt đầu bằng “File%” và kết thúc là “.txt” :

    Code:
    cat ‘File%’*’.txt’
    hoặc

    Code:
    cat File\%*.txt

    Redirecting standard input and output

    Nhiều chương trinh CLI sử dụng 1 tính năng được gọi là input/output redirection. Tính năng mạnh mẽ này cho phép chúng ta gắn các câu lệnh đơn giản lại với nhau để tạo thành 1 câu lệnh phức tạp.

    Thông thường, ta sử dụng các chương trình CLI và sau đó nhận kết quả từ chúng qua màn hình, nhưng màn hình không phải là nơi duy nhất mà các chương trình đó gửi kết quả của chúng tới, ta có thể chuyển hướng output của 1 vài lệnh tới file, thiết bị, ngay cả tới những câu lệnh khác.

    Standard output

    Các chương trình CLI thường gửi kết quả của chúng tới standard output, hay ngắn gọn là stdout. Mặc định, stdout đưa dữ liệu của nó tới màn hình, nhưng nếu ta muốn lưu trữ ouput trong 1 file, ta có thể :

    Code:
    ls > dir_listing.txt
    Khi đó dir_listing.txt sẽ chứa kết quả mà câu lệnh ls trả về.

    Mỗi lần bạn lặp lại lệnh trên, kết quả mới trả về từ ls sẽ ghi đè lên dữ liệu trước đó của dir_listing.txt, nếu ta muốn kết quả của mỗi câu lệnh sẽ được thêm vào cuối dir_listing.txt thay vì xóa dữ liệu cũ, ta dùng lệnh :

    Code:
    ls >> dir_listing.txt
    Ví dụ, ta muốn thêm nội dung của File1 vào cuỗi File2, ta dùng lệnh :

    Code:
    cat File1 >> File2
    Như đã nói, ta không những chuyển hướng output tới file, ta có thể chuyển hướng tới thiết bị.

    Ví dụ :

    Code:
    cat sound.wav > /dev/audio

    Câu lệnh trên đọc nội dung của sound.wav và gửi nội dung đó tới thiết bị /dev/audio, khi đó sound.wav sẽ được chơi.


    Standard input


    Nhiều lệnh chấp nhận input từ standard input, hay ngắn gọn là stdin. Theo mặc định, stdin đọc thông tin từ bàn phím, cũng như stdout, stdin có thể được chuyển hướng.

    Piping

    Ta có thể lấy output của chương trình này và chuyển hướng output đó như 1 input tới chương trình khác. Cách làm này được gọi là piping.

    Ví dụ.

    Code:
    ls | less
    Câu lệnh trên lấy stdout của ls chuyển tới less. Ưu điểm của cách làm này là, khi ls liệt qua ra qua nhiều file, và màn hình của chúng ta không đủ rộng để hiển thị hết chúng, vậy nên ta chuyển stdout tới less, khi đó ta có thể cuộn nội dung output của ls để xem được tất cả chúng.

    Ta có thể sử dụng piping với nhiều lệnh, nhưng lệnh thông dụng và hữu dụng nhất ta là grep. grep là chương trình kiểm tra mọi dòng trong stdin mà nó nhận và tìm kiếm với 1 mô hình các kí tự cụ thể nào đó, sau đó chuyển tới stdout mọi dòng phù hợp với mô hình.

    Ví dụ, ta muốn tìm trong 1 file applist.txt dòng nào xuất hiện từ “desktop”.

    Cách làm là ta sẽ đọc nội dung applist.txt và gửi nội dung đó tới grep và bảo grep tìm các dòng có từ “desktop”.

    Code:
    cat applist.txt | grep desktop
    Nếu ta muốn grep tìm kiếm không phân biệt chữ hoa và chữ thường, ta dùng lệnh :

    Code:
    cat applist.txt | grep -i desktop
    Ta cũng có thể gửi ouput của grep tới less để có thể cuộn nội dung output :

    Code:
    cat applist.txt | grep -i desktop | less
    Hoặc lưu output vào 1 file tên Desktop.txt :

    Code:
    cat app applist.txt | grep -i desktop > Desktop.txt

    Ví dụ trên cho thấy, piping thực sự mạnh mẽ, vì chỉ với những câu lệnh ngắn gọn, ta đã có thể nhanh chóng thực hiện được khá nhiều việc với nhiều mục đích khác nhau.

    Lấy exit code của 1 chương trình

    Khi 1 chương trình kết thúc, nó trả về 1 giá trị miêu tả trạng thái của nó khi kết thúc. Thường thì giá trị 0 miêu tả trạng thái thực thi thành công, giá trị khác 0 miêu tả trạng thái thực thi thất bại.
    Để lấy exit code của 1 chương trình vừa thực thi, ta sử dụng 1 biến đặc biệt là $?.
    Ví dụ, ta muốn lấy exit code của ls sau khi thực thi nó :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_5_1.png
Lần xem:	29
Size:		147.1 KB
ID:		10477

    Như hình mình họa trên, ta dùng lệnh :

    Code:
    echo $?
    Để lấy exit code của câu lệnh ls vừa thực thi, ở đây , biến $? có giá trị 0, miêu tả lệnh ls thực thi thành công.

    Khi thực thi lệnh ls lần thứ 2 với đường dẫn thư mục chỉ định là “wrongpath”, 1 đường dẫn không tồn tại, khi đó ls trả về thông báo lỗi và biến $? có giá trị là 2 , khác 0, miêu tả lệnh ls thực thi thất bại.

    Biến môi trường

    GNU/Linux cung cấp cho mỗi chương trình đang chạy 1 môi trường. Môi trường là tập hợp các cặp biến và giá trị. Cả tên biến và giá trị đều là chuỗi các kí tự. Theo quy ước, tên biến môi trường được đặt bằng các kí tự hoa.

    Một vài biến môi trường thường dùng như :

    • USER chứa tên tài khoản người dùng.
    • HOME chứa đường dẫn thư mục nhà của tài khoản đang dùng.
    • PATH chứa 1 danh sách các đường dẫn được ngăn cách bởi dấu 2 chấm, Linux sẽ tìm kiếm các lệnh mà bạn gọi tại các đường dẫn này.


    Shell cung cấp cho ta các phương thức để kiểm tra và thay đổi các biến môi trường 1 cách trực tiếp. Có 1 số shell sẽ có thể có các câu lệnh khác với shell khác để phục vụ mục đích này. Ở đây ta sử dụng cụ thể BASH. Để hiển thị tất cả các biến môi trường, ta sử dụng lệnh printenv.

    Ví dụ :

    Gọi lệnh printenv trên terminal :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_5_2.png
Lần xem:	22
Size:		479.3 KB
ID:		10478

    Để lấy giá trị từng biến môi trường, ta dùng lệnh echo :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		linux_5_3.png
Lần xem:	19
Size:		232.5 KB
ID:		10479

    Để thay đổi hoặc tạo mới 1 biến môi trường , sử dụng lệnh export với cú pháp :
    export [Tên biến]=[Giá trị]

    Nếu tên biến đã tồn tại, thì giá trị của nó sẽ được thay đổi, nếu tên biến chưa tồn tại, thì nó sẽ được tạo mới với giá trị ta nhập.

    Ví dụ, thay đổi giá trị biến môi trường HOME:

    Code:
    export HOME=/root
    Để liệt kê các biến môi trường bằng ngôn ngữ C/C++ , ta sử dụng 1 biến toàn cục environ được khai báo trong thư viện GNU C. Biến environ kiểu char**, là 1 con trỏ trỏ tới 1 mảng các chuỗi kí tự C-style có cấu trúc biến = giá trị.

    Ví dụ, 1 chương trình liệt kê các biến môi trường :
    C++ Code:
    1. #include <iostream>
    2.  
    3. // khai báo biến environ được khai báo ở 1 nơi khác
    4. extern char** environ;
    5.  
    6. int main(int argc, char** argv)
    7. {
    8.   char** var = environ;
    9.  
    10.   for(; var != NULL ; ++var)
    11.     {
    12.       std::cout << *var << std::endl;
    13.     }
    14.  
    15.  
    16.   return 0;
    17. }

    Để lấy giá trị của 1 biến môi trường, ta sử dụng hàm getenv(), hàm này nhận tham số là 1 chuỗi chứa tên của biến môi trường mà ta muốn lấy giá trị.

    C++ Code:
    1. #include <stdlib.h>
    2. #include <iostream>
    3.  
    4. int main(int argc, char** argv)
    5. {
    6.     // tên biến môi trường
    7.     const char* VarName = "HOME";
    8.     // lấy giá trị biến môi trường
    9.     char* VarVal = getenv(VarName);
    10.     // nếu biến môi trường tồn tại
    11.     if(VarVal != NULL)
    12.         std::cout << VarName << " = " << VarVal;
    13.     // nếu biến môi trường chưa tồn tại
    14.     else
    15.         std::cout << VarName << " chua ton tai.";
    16.  
    17.     return 0;
    18. }

    Sử dụng temporary file – file tạm

    Đôi khi chương trình của ta cần tạo 1 file tạm, để lưu trữ 1 lượng dữ liệu lớn chờ cho việc xử lý hoặc phục vụ cho 1 chương trình khác. Trên hệ điều hành GNU/Linux, các file tạm được lưu trong thư mục /tmp. Khi sử dụng file tạm, ta cần lưu ý :

    • Có thể nhiều hơn 1 thực thể chương trình của ta chạy đồng thời ( cùng user hoặc khác user ). Mỗi thực thể nên sử dụng tên file tạm khác nhau để tránh xung đột.
    • Quyền truy cập file nên được cài đặt sao cho các user trái phép không thể thay đổi quá trình thực thi của chương trình bằng cách thay đổi hoặc thay thế file tạm.
    • Tên file tạm nên được sinh ra theo cách mà tên file không thể được đoán trước từ user, vì nếu 1 attacker có thể đoán được tên file tạm, attacker đó có thể thay đổi hoặc thay thế file tạm, làm ảnh hưởng tới chương trình sử dụng file tạm đó.


    GNU/Linux cung cấp 2 hàm, mkstemp và tmpfile để giúp ta trong vấn đề này.

    GNU/Linux cũng cung cấp 1 số hàm khác, nhưng chúng bị phản đối vì chưa đảm bảo các vấn đề cần lưu ý ở trên, nên ta chỉ nên sử dụng 2 hàm trên.

    Sử dụng mkstemp

    Hàm mkstemp tạo file tạm với tên duy nhất theo 1 mẫu tên cho trước và file tạm đó sẽ chỉ được truy cập bởi user hiện tại. Mẫu tên là 1 chuỗi kí tự kết thúc bởi “XXXXXX”. mkstemp sẽ thay thế mỗi kí tự X sao cho tên mỗi file tạm là duy nhất.

    Sau khi tạo file tạm, mkstemp sẽ return 1 con trỏ file, qua con trỏ này ta có thể đọc hoặc viết file tạm.

    File tạm mà mkstemp tạo không tự động bị xóa. Bởi vậy ta cần lưu ý xóa file tạm ngay khi không cần nữa.

    Nếu file tạm chỉ được sử dụng nội bộ, tức là không có sự can thiệp và xử lý của các chương trình khác, ta nên sử dụng hàm unlink trong thư viện <unistd.h> cho file tạm ngay sau khi nó được tạo bởi mkstemp. Hàm unlink sẽ xóa 1 file theo đường dẫn mà ta truyền vào hàm. Nhưng file trong linux là reference-counted, nghĩa là nó sẽ chưa được xóa cho tới khi vẫn còn được mở. Bởi vậy, chương trình của ta vẫn sử dụng file tạm đó như bình thường, và ngay sau khi ta đóng file tạm, nó sẽ tự động được xóa. Hơn nữa, vì Linux sẽ đóng file đang được mở bởi chương trình nếu chương trình bị kết thúc đột ngột, nên file tạm cũng sẽ được xóa tự động ngay cả trong trường hợp này.

    Ví dụ. Tạo, ghi và đọc file tạm :

    C++ Code:
    1. #include <stdlib.h>
    2. #include <iostream>
    3.  
    4. // khai báo 1 kiểu int miêu tả con trỏ file
    5. typedef int HFILE;
    6.  
    7. // hàm tạo và ghi dữ liệu vào file tạm
    8. HFILE WriteTempFile(char* buffer, unsigned int length)
    9. {
    10.     // mẫu tên file tạm
    11.     char FileName[] = "/tmp/temp_XXXXXX";
    12.     // tạo file tạm
    13.     HFILE hFile = mkstemp(FileName);
    14.    
    15.     // unlink file tạm để nó có thể tự động được xóa
    16.     unlink(FileName);
    17.  
    18.     // ghi độ dài dữ liệu vào đầu file tạm
    19.     write(hFile, &length, sizeof(length));
    20.  
    21.     // khi dữ liệu vào file tạm
    22.     write(hFile, buffer, length);
    23.  
    24.     // trả về con trỏ file tạm
    25.     return hFile;
    26. }
    27.  
    28. // hàm đọc và xóa file tạm, trả về 1 buffer kiểu char* được cấp phát động, nên ta cần tự giải phóng buffer
    29. char* ReadTempFile(HFILE hFile, unsigned int& length)
    30. {
    31.     // khai báo buffer
    32.     char* buffer = NULL;
    33.  
    34.     // truyển con trỏ đọc file tới đầu file
    35.     lseek(hFile, 0, SEEK_SET);
    36.  
    37.     // đọc độ dài dữ liệu
    38.     read(hFile, &length, sizeof(length));
    39.  
    40.     // cấp phát động cho buffer
    41.     buffer = (char*) malloc(length * sizeof(char));
    42.  
    43.     // đọc dữ liệu từ file tạm và ghi vào buffer
    44.     read(hFile, buffer, length);
    45.    
    46.     // đóng file
    47.     close(hFile);
    48.  
    49.     return buffer;
    50. }
    51.  
    52. int main(int argc, char** argv)
    53. {
    54.     // dữ liệu cần ghi vào file tạm
    55.     char buffer[] = "Testing"; 
    56.  
    57.     // ghi dữ liệu vào file tạm
    58.     HFILE hTempFile = WriteTempFile(buffer, sizeof(buffer));
    59.    
    60.     unsigned int length = 0;
    61.     // đọc và in dữ liệu từ file tạm
    62. char* data = ReadTempFile(hTempFile, length);
    63. std::cout << data << std::endl;
    64. free(data);
    65.  
    66.     return 0;
    67. }

    Sử dụng tempfile

    Nếu ta chỉ muốn sử dụng thư viện I/O của C và file tạm sử dụng nội bộ, ta có thể sử dụng tempfile. Hàm tempfile tạo file tạm đã được unlink sẵn, nghĩa là nó sẽ tự động được xóa khi ta đóng file và return 1 con trỏ file mà ta có thể sử dụng các hàm trong thư viện I/O của C để xử lý.
    Đã được chỉnh sửa lần cuối bởi luc13aka47 : 07-11-2012 lúc 10:33 AM.

  7. #7
    Ngày gia nhập
    08 2010
    Bài viết
    2

    quả là 1 kho báu quí giá với người mới học linux như em, cám ơn bác

  8. #8
    Ngày gia nhập
    12 2008
    Nơi ở
    Hà Nội
    Bài viết
    374

    Contents
    Viết và sử dụng các thư viện. 1
    Thư viện tĩnh. 1
    Thư viện động. 3
    Sử dụng LD_LIBRARY_PATH.. 5
    Thư viện chuẩn. 6
    Sự phụ thuộc giữa các thư viện. 7
    Ưu - nhược điểm giữa thư viện tĩnh và thư viện động. 8
    Dynamic Loading and Unloading. 8



    Viết và sử dụng các thư viện


    Có 2 loại thư viện :

    • Thư viện tĩnh ( archive hoặc static library ), khi liên kết với loại thư viện này, chương trình sẽ có kích thước lớn hơn, khó nâng cấp nhưng dễ triển khai và có tính độc lập.
    • Thư viện động (Shared Libraries hoặc Dynamically linked library hoặc shared object ), khi liên kết với loại thư viện này, chương trình sẽ có kích thước nhỏ, dễ nâng cấp, nhưng khó triển khai và có tính phụ thuộc vào thư viện.


    Thư viện tĩnh


    Một archive ( thư viện tĩnh ) đơn giản là 1 tập hợp các object file được lưu trữ trong 1 file. Một archive file cũng gần giống với 1 *.lib file trong Windows.

    Khi ta cung cấp 1 archive cho linker, nó sẽ tìm kiếm trong archive những object file mà nó cần, sau đó chiết xuất chúng và liên kết vào chương trình của ta giống như ta cung cấp trực tiếp 1 object file.

    Ta có thể tạo 1 archive file bằng việc sử dụng lệnh ar. Một archive file có đuôi là *.a ; theo quy ước, có tên bắt đầu là “lib”.

    Ví dụ :

    Code:
    ar cr libtest.a test1.o test2.o
    Cờ cr nói cho ar biết ta cần tạo 1 archive file. Bây giờ ta có thể sử dụng option -ltest với gcc hoặc g++ ( tùy chọn này có nghĩa là ta cung cấp cho gcc hoặc g++ thư viện libtest.a để nó sử dụng trong quá trình biên dịch chương trình của ta ; ví dụ, tên thư viện là libgido.a, thì dùng option -lgido, gcc hoặc g++ sẽ tự hiểu là ta cung cấp libgido.a ).


    Khi biên dịch 1 object file bằng gcc hoặc g++, nên cung cấp archive file sau khi đã cung cấp object file.


    Ví dụ :

    Ta có các file mã nguồn sau :

    test.c
    C Code:
    1. int f ()
    2.   {
    3.   return 3;
    4.   }
    app.c
    C Code:
    1. int main ()
    2.   {
    3.   return f ();
    4.   }

    Ta tạo 1 archive tên libtest.a từ test.c. Sau đó biên dịch app.c và liên kết với libtest.a bằng lệnh :

    Code:
    gcc -o app -L. -ltest app.o
    Khi đó ta sẽ nhận được lỗi :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		topic186.1.png
Lần xem:	19
Size:		689.1 KB
ID:		10545


    Giải thích cho điều này như sau :

    gcc hoặc g++ khi gặp option cung cấp archive ( ở đây là “-L. - ltest” ), nó sẽ tìm khai báo của hàm hoặc biến được sử dụng trong object file ( ở đây là app.o ) mà chưa được khai báo ( ở đây là hàm f() ) trong archive đó ; nói cách khác, gcc và g++ sẽ tìm những biến và hàm được sử dụng mà chưa khai báo trong object file trong archive file để liên kết. Có điều, trong lệnh trên, ta cung cấp archive file trước object file (“-L. - ltest” trước “app.o” ), nên khi gặp archive file trong dòng lệnh, gcc và g++ không liên kết được gì vì chưa có object file, đến khi gặp object file thì nó lại không liên kết ; vì chỉ gặp archive file thì nó mới liên kết.

    Bởi vậy ta nên cung cấp object file trước archive file khi biên dịch bằng gcc và g++.

    Câu lệnh trên sửa lại thành :

    Code:
       gcc -o app app.o -L. -ltest
    Khi đó sẽ như ta mong muốn :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		topic186.2.png
Lần xem:	11
Size:		695.6 KB
ID:		10546



    Thư viện động


    Một thư viện động, tương tư như archive ( thư viện tĩnh ), là 1 tập hợp các object file. Tuy nhiên, có nhiều khác biệt giữa 2 loại thư viện này :

    • Khác biệt thứ nhất : Thư viện động được liên kết vào 1 chương trình, thì chương trình đó không thực sự chứa mã của thư viện động. Thay vì vậy, chương trình chỉ chứa 1 tham chiếu tới thư viện động đó. Hơn nữa, nếu nhiều chương trình cùng liên kết tới cùng 1 thư viện động, thì chúng không chứa mã của thư viện động, mà cùng tham chiếu tới thư viện đó.
    • Khác biệt thứ 2 : Khi linker liên kết 1 chương trình tới 1 thư viện động, nó không chọn ra phần cần thiết trong thư viện động để liên kết như thư viện tĩnh, mà toàn bộ thư viện động sẽ được liên kết tới chương trình đó.


    Để tạo 1 object file mà ta dự định sẽ biên dịch nó thành 1 thư viện động, ta cần biên dịch với tùy chọn -fPIC.

    Ví dụ :
    Code:
    gcc -c -fPIC test.c
    Ta sẽ được object file tên test.o phục vụ cho việc tạo thư viện động.

    PIC là viết tắt của Position-Independent Code. Các hàm trong thư viện động có thể sẽ được load ở các địa chỉ khác nhau trong vùng bộ nhớ của các chương trình khác nhau, vậy nên code của thư viện động phải không phụ thuộc vào địa chỉ bộ nhớ ( hoặc vị trí ) khi nó được load.

    Để tạo 1 thư viện động từ các object file dành riêng cho việc tạo thư viện động ( như test.o ở trên ), ta dùng lệnh :

    Code:
    gcc -shared -fPIC -o libtest.so test.o test1.o
    Tùy chọn -shared nói cho gcc hoặc g++ biết tạo ra 1 thư viện động thay vì 1 file thực thi bình thường. Thư viện động có đuôi là *.so, viết tắt của shared object. Giống như thư viện tĩnh, tên của thư viện động theo quy ước, bắt đầu bằng “lib”.

    Để liên kết thư viện động, cũng tương tự như thư viện tĩnh, ta dùng lệnh :

    Code:
    gcc -o app app.o -L. -ltest
    gcc hoặc g++ sẽ tìm libtest.so hoặc libtest.o trong thư viện đang làm việc trước ( vì có tùy chọn -L. ) , sau đó là các thư viện chứa thư viện chuẩn, khi nó tìm được 1 trong 2, thì không tìm nữa. Nếu như cả 2 libtest.o và libtest.so cùng tồn tại, giả sử trong cùng thư mục đang làm việc, thì gcc hoặc g++ sẽ chọn thư viện động, libtest.so. Nếu ta tường minh cung cấp thêm 1 tùy chọn nữa là -static trong câu lệnh, thì gcc hoặc g++ sẽ chọn thư viện tĩnh, libtest.o, ví dụ :

    Code:
    gcc -static -o app app.o -L. - ltest
    Để chương trình app thực thi được, ta cần di chuyển libtest.so vào thư mục /lib.

    Ta sử dụng lệnh ldd để liệt kê các thư viện động mà 1 chương trình tham chiếu tới, và thư viện động nào đã có, thư viện nào không.

    Ví dụ :
    Code:
    ldd ./app
    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		topic186.3.png
Lần xem:	10
Size:		715.1 KB
ID:		10547


    Sử dụng LD_LIBRARY_PATH

    Khi ta liên kết 1 chương trình với 1 thư viện động, linker không đặt đường dẫn đầy đủ của thư viện động trong file thực thi, nó chỉ đặt tên của thư viện động. Khi chương trình thực thi, hệ thống tìm các thư viện động và load nó. Hệ thống mặc định chỉ tìm trong thư mục /lib và /usr/lib. Nếu thư viện động không nằm trong những thư mục đó, hệ thống sẽ không thực thi chương trình.
    Một giải pháp cho vấn đề này là sử dụng tùy chọn -Wl và -rpath khi liên kết chương trình.
    Giả sử, khi ta liên kết chương trình bằng câu lệnh :

    Code:
    gcc -o app app.o -L. -ltest -Wl,-rpath,/usr/local/lib
    Thì khi chương trình app thực thi, hệ thống ngoài việc tìm kiếm thư viện động trong các thư mục chứa thư viện chuẩn, sẽ tìm kiếm thêm cả thư mục /usr/local/lib.

    Ví dụ, ta muốn khi thực thi chương trình, hệ thống sẽ tìm kiếm thư viện động trong thư mục đang làm việc hiện tại trên terminal :

    Click vào hình ảnh để lấy hình ảnh lớn

Tên:		topic186.4.png
Lần xem:	5
Size:		662.4 KB
ID:		10544

    Một giải pháp khác cho vấn đề trên là thay đổi giá trị của biến môi trường LD_LIBRARY_PATH. Giá trị của LD_LIBRARY_PATH là danh sách các đường dẫn ngăn cách nhau bởi dấu 2 chấm ( : ).

    Ví dụ, giá trị của LD_LIBARY_PATH là /usr/local/lib:/opt/lib , thì hệ thống sẽ tìm các thư viện động trong 2 thư mục /usr/local/lib và /opt/lib trước khi tìm trong các thư mục chứa thư viện chuẩn.

    Thư viện chuẩn


    Hầu hết khi ta sử dụng các hàm trong thư viện chuẩn của C, ta không phải chỉ định các thư viện chứa các hàm đó khi biên dịch chương trình, vì GCC tự động liên kết chương trình của ta tới thư viện runtime C, libc. Tuy nhiên, với thư viện hàm toán học chuẩn của C không nằm trong libc, nó nằm trong 1 thư viện riêng là libm, bởi vậy khi sử dụng các hàm trong thư viện toán học của C, <math.h>, ta cần cung cấp tương minh thư viện này cho GCC khi biên dịch.

    Ví dụ, trong compute.c sử dụng các hàm sin và cos, là những hàm trong thư viện toán học <math.c>, khi biên dịch ta cần :

    Code:
    gcc -o compute compute.c –lm
    Với C++, g++ cũng tự động liên kết chương trình của ta tới thư viện runtime C++, libstdc++ ; và khi biên dịch bằng g++, ta không cần tường minh cung cấp thư viện toán học như GCC nữa.

    Sự phụ thuộc giữa các thư viện


    Một thư viện thường phụ thuộc vào các thư viện khác. Ví dụ, nhiều phiên bản GNU/Linux có thư viện libtiff, 1 thư viện chứa các hàm đọc, viết file ảnh có định dạng TIFF ; libtiff lại sử dụng thư viện libjpge (JPEGimage routines) và libz (compression routines).

    Ví dụ, ta có 1 file mã nguồn tên tifftest.c sau :

    C Code:
    1. #include <stdio.h>
    2.   #include <tiffio.h>
    3.    
    4.   int main (int argc, char** argv)
    5.   {
    6.   TIFF* tiff;
    7.   tiff = TIFFOpen (argv[1], “r”);
    8.   TIFFClose (tiff);
    9.   return 0;
    10.   }

    Để biên dịch chương trình và liên kết với thư viện libtiff :

    Code:
    gcc -o tifftest tifftest.c –ltiff
    Theo mặc định, gcc sẽ liên kết chương trình với thư viện động libtiff ( có cả phiên bản thư viện tĩnh , libtiff.a ) được tìm thấy tại /usr/lib/libtiff.so và vì libtiff sử dụng 2 thư viện động libjpge và libz ( 2 thư viện này cũng có phiên bản thư viện tĩnh ), nên 2 thư viện này cũng được gcc liên kết với chương trình ( vì thư viện động có thể trỏ tới các thư viện động khác và phụ thuộc vào nó ). Để kiểm chứng điều này, ta sử dụng ldd để liệt kê các thư viện động mà chương trình testtiff tham chiếu tới :

    Code:
    ldd tifftest
      libtiff.so.3 => /usr/lib/libtiff.so.3 (0x4001d000)
      libc.so.6 => /lib/libc.so.6 (0x40060000)
      libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x40155000)
      libz.so.1 => /usr/lib/libz.so.1 (0x40174000)
      /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
    Với thư viện tĩnh thì khác, nó không thể trỏ tới thư viện khác.

    Ví dụ, ta cố gắng liên kết chương trình với thư viện tĩnh libtiff.o bằng cách thêm tùy chọn -static :

    Code:
    gcc -static -o tifftest tifftest.c -ltiff
      /usr/bin/../lib/libtiff.a(tif_jpeg.o): In function ‘TIFFjpeg_error_exit’:
      tif_jpeg.o(.text+0x2a): undefined reference to ‘jpeg_abort’
      /usr/bin/../lib/libtiff.a(tif_jpeg.o): In function ‘TIFFjpeg_create_compress’:
      tif_jpeg.o(.text+0x8d): undefined reference to ‘jpeg_std_error’
      tif_jpeg.o(.text+0xcf): undefined reference to ‘jpeg_CreateCompress’
      ...
    Ta thấy rằng GCC không tìm thấy những hàm của thư viện libjpge và libz mà libtiff sử dụng, vì thư viện tĩnh libtiff.o không trỏ được tới thư viện khác, nên GCC không được cung cấp các thư viện để liên kết.

    Để liên kết chương trình với thư viện tĩnh libtiff, ta cần cung cấp cả các thư viện mà libtiff sử dụng :

    Code:
    gcc -static -o tifftest tifftest.c -ltiff -ljpeg -lz
    Đôi khi, 2 thư viện tĩnh phụ thuộc lẫn nhau. Trong trường hợp này, khi cung cấp cho linker, ta cần cung cấp nhiều lần 1 thư viện trong dòng lệnh.

    Ví dụ, libfoo.a và libbar.a phụ thuộc lẫn nhau, khi liên kết chúng với app.o, ta cần dùng lệnh :

    Code:
    gcc -o app app.o -lfoo -lbar –lfoo


    Ưu - nhược điểm giữa thư viện tĩnh và thư viện động


    Một lợi thế lớn của thư viện động là tích kiệm bộ nhớ hệ thống. Nếu ta cài đặt 10 chương trình, tất cả chúng đều tham chiếu tới 1 thư viện động, sẽ tích kiệm được lượng bộ nhớ đáng kể. Nếu ta sử dụng thư viện tĩnh thay thế, thì thư viện tĩnh đó sẽ được chứa trong cả 10 chương trình, gẫy ra sự lãng phí. Sự tích kiệm này còn giảm thời gian tải chương trình từ internet.

    Một lợi thế lớn khác của thư viện động là dễ dàng nâng cấp. Ví dụ ta có 1 thư viện động mà nhiều chương trình phụ thuộc vào nó, nếu ta tìm thấy lỗi trong thư viện đó, ta chỉ cần nâng cấp thư viện, và khi đó , tất cả chương trình phụ thuộc vào nó sẽ được sửa ; thay vì phải liên kết lại tất cả chương trình nếu sử dụng thư viện tĩnh.

    Tuy nhiên, lợi thế thứ 2 trên cũng có thể là nhược điểm của thư viện động. Ví dụ, ta muốn xây dựng 1 chương trình mà khi người dùng nâng cấp các thư viện động, sẽ không ảnh hưởng tới chương trình của ta, thì thư viện tĩnh là sự lựa chọn tốt hơn.

    Một nhược điểm nữa của thư viện động là quá trình cài đặt dài dòng và bất tiện. Để cài đặt các thư viện động, ta cần yêu cầu người dùng có quyền admin, sau đó di chuyển các thư viện động tới các thư mục chứa các thư viện chuẩn ( /lib và /usr/lib ) ; hơn nữa, nếu ta yêu cầu người dùng thay đổi giá trị của biến môi trường LD_LIBRARY_PATH để phục vụ cho việc thực thi chương trình của ta, thì sẽ gây bất tiện cho người dùng.

    Dynamic Loading and Unloading


    Đôi khi ta muốn load 1 thư viện tại runtime mà không cần phải liên kết tường minh tới thư viện đó. Ví dụ, 1 ứng dụng hỗ trợ tính năng được gọi là plugin, như 1 trình duyệt web. Trình duyệt cho phép bên thứ 3 phát triển và tạo các plugin để cung cấp thêm chức năng cho trình duyệt. Bên thứ 3 tạo 1 thư viện động và đặt nó vào 1 vị trí cho trước. Trình duyệt sẽ tự động load các thư viện đó.

    Ví dụ, ta muốn dynamic load thư viện libm :

    Ta cần :


    • Sử dụng hàm dlopen() để dynamic load 1 thư viện tại runtime, trả về NULL nếu thất bại. dlopen() chỉ load thư viện nếu nó chưa được load, nếu nó đã được load rồi thì hàm dlopen() sẽ tăng reference count của thư viện.
    • Sử dụng hàm dlsys() để lấy địa chỉ của hàm hoặc biến trong bộ nhớ sau khi thư viện được load, trả về NULL nếu thất bại.
    • dlclose() để giảm reference count của thư viện đã load (reference count bằng 0 thì thư viện được unload ).
    • dlerror() để lấy thông tin lỗi nếu các hàm trong thư viện <dlfcn.h> thất bại, trả về NULL nếu không có lỗi.
    • Nếu ta viết thư viện động bằng C++ và muốn nó chứa các hàm hoặc các biến sẽ được truy cập từ bên ngoài, thì ta nên khai báo với “extern “C””, ví dụ :


    C++ Code:
    1. extern “C” void foo ();
    C Code:
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <dlfcn.h>
    4.  
    5. int
    6. main(int argc, char **argv)
    7. {
    8.     void *handle;
    9.     double (*cosine)(double);
    10.     char *error;
    11.  
    12.    handle = dlopen("libm.so", RTLD_LAZY);
    13.     if (!handle) {
    14.         fprintf(stderr, "%s\n", dlerror());
    15.         exit(EXIT_FAILURE);
    16.     }
    17.  
    18.    dlerror();    /* Clear any existing error */
    19.  
    20.    /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
    21.        would seem more natural, but the C99 standard leaves
    22.        casting from "void *" to a function pointer undefined.
    23.        The assignment used below is the POSIX.1-2003 (Technical
    24.        Corrigendum 1) workaround; see the Rationale for the
    25.        POSIX specification of dlsym(). */
    26.  
    27.    *(void **) (&cosine) = dlsym(handle, "cos");
    28.  
    29.    if ((error = dlerror()) != NULL)  {
    30.         fprintf(stderr, "%s\n", error);
    31.         exit(EXIT_FAILURE);
    32.     }
    33.  
    34.    printf("%f\n", (*cosine)(2.0));
    35.     dlclose(handle);
    36.     exit(EXIT_SUCCESS);
    37. }
    Đã được chỉnh sửa lần cuối bởi luc13aka47 : 20-11-2012 lúc 08:12 PM.

Các đề tài tương tự

  1. Tìm người hợp tác làm trình biên dịch C trên linux
    Gửi bởi hardwire trong diễn đàn Việc làm IT(tự do)
    Trả lời: 16
    Bài viết cuối: 22-03-2012, 09:17 PM
  2. Game Cách gọi trình soạn thảo word trong C#?
    Gửi bởi linh_kute trong diễn đàn Thắc mắc lập trình C#
    Trả lời: 1
    Bài viết cuối: 12-02-2012, 10:56 PM
  3. Tạo makefile để biên dịch chương trình C trên linux?
    Gửi bởi thanhx0kjt trong diễn đàn Thắc mắc lập trình C/C++ trên Linux
    Trả lời: 10
    Bài viết cuối: 04-11-2010, 10:09 AM
  4. Cách biên dịch XUnikey trên Linux
    Gửi bởi cSharp trong diễn đàn Thắc mắc lập trình C/C++ trên Linux
    Trả lời: 1
    Bài viết cuối: 17-07-2010, 10:48 AM
  5. Lập trình C trong linux. Cách biên dịch chương trình C trên Linux như thế nào?
    Gửi bởi thangbn trong diễn đàn Thắc mắc lập trình C/C++ trên Linux
    Trả lời: 5
    Bài viết cuối: 30-05-2009, 11:38 AM

Tags của đề tài này

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn