Các tùy chọn dòng lệnh GCC không phổ biến nhưng hữu ích

theanh

Administrator
Nhân viên
Các công cụ phần mềm thường cung cấp nhiều tính năng, nhưng - như hầu hết các bạn sẽ đồng ý - không phải tất cả các tính năng của chúng đều được mọi người sử dụng. Nói chung, không có gì sai trong điều đó, vì mỗi người dùng có yêu cầu riêng và họ chỉ sử dụng các công cụ trong phạm vi đó. Tuy nhiên, luôn tốt khi tiếp tục khám phá các công cụ bạn sử dụng vì bạn không bao giờ biết khi nào một trong các tính năng của chúng có thể hữu ích, giúp bạn tiết kiệm một số thời gian quý báu trong quá trình này.

Một ví dụ điển hình: trình biên dịch. Một trình biên dịch ngôn ngữ lập trình tốt luôn cung cấp vô số tùy chọn, nhưng người dùng thường chỉ biết và sử dụng một tập hợp hạn chế. Cụ thể, nếu bạn là nhà phát triển ngôn ngữ C và sử dụng Linux làm nền tảng phát triển, rất có thể bạn sẽ sử dụng trình biên dịch gcc, cung cấp danh sách vô tận các tùy chọn dòng lệnh.

Bạn có biết rằng nếu muốn, bạn có thể yêu cầu gcc lưu đầu ra ở mỗi giai đoạn của quá trình biên dịch không? Bạn có biết tùy chọn -Wall mà bạn sử dụng để tạo cảnh báo không bao gồm một số cảnh báo cụ thể không? Có nhiều tùy chọn gcc dòng lệnh không thường được sử dụng nhưng có thể cực kỳ hữu ích trong một số trường hợp nhất định, ví dụ như khi gỡ lỗi mã.

Vì vậy, trong bài viết này, chúng tôi sẽ đề cập đến một số tùy chọn như vậy, cung cấp tất cả các chi tiết cần thiết và giải thích chúng thông qua các ví dụ dễ hiểu khi cần thiết.

Nhưng trước khi tiếp tục, hãy nhớ rằng tất cả các ví dụ, lệnh và hướng dẫn được đề cập trong hướng dẫn này đều đã được thử nghiệm trên Ubuntu 16.04 LTS và phiên bản gcc mà chúng tôi đã sử dụng là 5.4.0.


Xem đầu ra trung gian trong mỗi giai đoạn biên dịch​

Bạn có biết rằng, nói chung, có tổng cộng bốn giai đoạn mà mã C của bạn trải qua khi bạn biên dịch nó bằng trình biên dịch gcc không? Đó là tiền xử lý, biên dịch, lắp ráp và liên kết. Sau mỗi giai đoạn, gcc tạo ra một tệp đầu ra tạm thời được chuyển giao cho giai đoạn tiếp theo. Bây giờ, tất cả những tệp này đều là tệp tạm thời được tạo ra và do đó chúng ta không thể thấy chúng - tất cả những gì chúng ta thấy là chúng ta đã phát hành lệnh biên dịch và nó tạo ra tệp nhị phân/tệp thực thi mà chúng ta có thể chạy.

Nhưng giả sử, nếu trong khi gỡ lỗi, có yêu cầu xem mã trông như thế nào sau, chẳng hạn, giai đoạn tiền xử lý. Khi đó, bạn sẽ làm gì? Vâng, điều tốt là trình biên dịch gcc cung cấp tùy chọn dòng lệnh mà bạn có thể sử dụng trong lệnh biên dịch chuẩn của mình và nếu không, bạn sẽ nhận được các tệp trung gian bị trình biên dịch xóa. Tùy chọn chúng ta đang nói đến là -save-temps.

Đây là những gì trang hướng dẫn gcc nói về tùy chọn này:
Mã:
Lưu trữ vĩnh viễn các tệp trung gian "tạm thời" thông thường; đặt
 chúng vào thư mục hiện tại và đặt tên dựa trên tệp
 nguồn. Do đó, biên dịch foo.c với -c -save-temps tạo ra các tệp
 foo.i và foo.s, cũng như foo.o. Điều này tạo ra một tệp đầu ra
 foo.i được xử lý trước mặc dù trình biên dịch hiện thường sử dụng một
 bộ xử lý trước tích hợp.

 Khi được sử dụng kết hợp với tùy chọn dòng lệnh -x,
 -save-temps đủ hợp lý để tránh ghi đè lên tệp
 nguồn đầu vào có cùng phần mở rộng với tệp trung gian. Tệp trung gian tương ứng có thể được lấy bằng cách đổi tên tệp nguồn trước khi sử dụng -save-temps.
Sau đây là một lệnh ví dụ sẽ cho bạn biết cách sử dụng tùy chọn này:
Mã:
gcc -Wall [B]-save-temps[/b] test.c -o test-exec
Và đây là cách tôi xác minh rằng tất cả các tệp trung gian thực sự được tạo ra sau khi lệnh được đề cập ở trên được thực thi:



Vì vậy, như bạn có thể thấy trong ảnh chụp màn hình ở trên, các tệp test.i, test.stest.o được tạo ra bởi tùy chọn -save-temps. Các tệp này tương ứng với các giai đoạn tiền xử lý, biên dịch và liên kết.


Chuẩn bị sẵn sàng cho việc gỡ lỗi và lập hồ sơ mã của bạn​

Có các công cụ chuyên dụng cho phép bạn gỡ lỗi và lập hồ sơ mã nguồn của mình. Ví dụ,gdb được sử dụng cho mục đích gỡ lỗi, trong khigprof là một công cụ phổ biến cho mục đích lập hồ sơ. Nhưng bạn có biết gcc cung cấp các tùy chọn dòng lệnh cụ thể để chuẩn bị sẵn sàng cho việc gỡ lỗi và lập hồ sơ mã của bạn không?

Chúng ta hãy bắt đầu với việc gỡ lỗi. Để có thể sử dụng gdb để gỡ lỗi mã, bạn sẽ phải biên dịch mã của mình bằng tùy chọn dòng lệnh -g được cung cấp bởi trình biên dịch gcc. Về cơ bản, tùy chọn này cho phép gcc tạo thông tin gỡ lỗi mà gdb yêu cầu để gỡ lỗi thành công chương trình của bạn.

Trong trường hợp bạn định sử dụng tùy chọn này, bạn nên xem qua các chi tiết mà trang hướng dẫn gcc cung cấp về tùy chọn này - một số trong số đó có thể chứng minh là quan trọng trong một số trường hợp. Ví dụ, sau đây là một đoạn trích được lấy từ trang hướng dẫn:
Mã:
GCC cho phép bạn sử dụng -g với -O. Các phím tắt được sử dụng bởi mã 
 được tối ưu hóa đôi khi có thể tạo ra kết quả đáng ngạc nhiên: một số biến 
 bạn đã khai báo có thể không tồn tại; luồng điều khiển có thể tạm thời di chuyển 
 đến nơi bạn không mong đợi; một số câu lệnh có thể không được thực thi 
 vì chúng tính toán kết quả hằng số hoặc giá trị của chúng đã có sẵn 
; một số câu lệnh có thể thực thi ở những nơi khác nhau vì
 chúng đã được di chuyển ra khỏi vòng lặp.

 Tuy nhiên, nó chứng minh rằng có thể gỡ lỗi đầu ra được tối ưu hóa. Điều này
 làm cho việc sử dụng trình tối ưu hóa cho các chương trình có thể
 có lỗi trở nên hợp lý.
Không chỉ gdb, việc biên dịch mã của bạn bằng tùy chọn -g cũng mở ra khả năng sử dụng công cụ memcheck của Valgrind với toàn bộ tiềm năng của nó. Đối với những ai chưa biết, memcheck được các lập trình viên sử dụng để kiểm tra rò rỉ bộ nhớ (nếu có) trong mã của họ. Bạn có thể tìm hiểu thêm về công cụ này tại đây.

Tiếp theo, để có thể sử dụng gprof để lập hồ sơ mã, bạn phải biên dịch mã của mình bằng tùy chọn dòng lệnh -pg. Nó cho phép gcc tạo mã bổ sung để ghi thông tin lập hồ sơ, thông tin này được gprof yêu cầu để phân tích mã. "Bạn phải sử dụng tùy chọn này khi biên dịch các tệp nguồn mà bạn muốn có dữ liệu về và bạn cũng phải sử dụng tùy chọn này khi liên kết", trang hướng dẫn gcc nêu rõ. Để tìm hiểu thêm về cách thực hiện lập hồ sơ mã bằng gprof, hãy truy cập hướng dẫn chuyên dụng này trên trang web của chúng tôi.

Lưu ý: Việc sử dụng cả tùy chọn -g-pg đều tương tự như cách sử dụng tùy chọn -save-temps trong phần trước.


Kết luận​

Nếu bạn không phải là chuyên gia về gcc, tôi chắc rằng bạn đã học được điều gì đó mới mẻ từ bài viết này. Hãy thử các tùy chọn này và xem chúng hoạt động như thế nào. Trong khi đó, hãy chờ phần tiếp theo trong loạt hướng dẫn này, trong đó chúng ta sẽ thảo luận thêm về các tùy chọn dòng lệnh gcc thú vị và hữu ích như vậy.
 
Back
Bên trên