Môi Trường Tích Hợp (IDE) Không Phải Là Lựa Chọn Duy Nhất Của Lập Trình Viên (Kỳ 5)
Kỳ nghỉ Quốc khánh vừa qua, tôi đã xử lý rất nhiều việc và gần như không có lúc nào rảnh rỗi. Hiện tại muốn tiếp tục viết tiếp loạt bài này nhưng cảm thấy thiếu chút hào hứng.
Nếu tiếp tục tập trung vào GNU Make thì có vẻ hơi lạc đề. Chủ đề gốc tôi muốn bàn luận là khi rời bỏ IDE, lập trình viên nên xử lý vấn đề như thế nào. GNU Make chỉ là điểm khởi đầu. Càng viết càng thấy nội dung phong phú, nhưng lại cảm giác như chưa truyền tải được gì cụ thể. Những bạn đọc tinh ý chắc hẳn đã tự tìm tài liệu hướng dẫn GNU Make tiếng Trung để nghiên cứu, tôi tin rằng khi kết hợp với các dự án các bạn đã từng làm, sẽ phát hiện ra bao hàm chứa rất nhiều tinh hoa. Về phía những bạn thích trải nghiệm văn hóa “ăn nhanh”, có lẽ đang chờ đợi phần tiếp theo của tôi. Vậy hãy mượn một câu trích dẫn trên trang chủ Vim để bắt đầu:
“Vim không phải là một phần mềm soạn thảo được thiết kế để dắt tay người dùng từng bước. Nó là một công cụ, và việc sử dụng nó đòi hỏi phải học hỏi.”
Đúng vậy, GNU Make cũng vậy, các công cụ lập trình khác cũng đều như thế. Đã là công cụ thì nhất định phải đầu tư chi phí học tập. Nếu bạn cảm thấy việc sử dụng công cụ nào đó không cần bất kỳ chi phí học tập nào, thì chắc hẳn bạn đang đánh mất điều gì đó. Điều này có thể bản thân bạn chưa nhận ra mà thôi.
Để tận dụng máy tính giúp hoàn thành mục tiêu, thực ra có rất nhiều phương pháp. Có phương pháp của người dùng phổ thông, và phương pháp của lập trình viên. Phương pháp của lập trình viên là dạy cho máy tính làm việc thay mình; phương pháp của người dùng phổ thông là dựa vào máy tính để hỗ trợ mình. Trong IDE, đôi khi chúng ta cũng cố gắng sử dụng các cách đặc biệt để dạy máy tính làm việc gì đó. Theo quan điểm cá nhân, C++ cùng các tính năng độc đáo khai thác sâu, xây dựng nên kho thư viện mẫu phong phú phần nào bắt nguồn từ điều này. Ví dụ như thư viện Boost::Spirit trong boost giúp lập trình viên C++ viết các biểu thức gần giống với BNF, từ đó sinh ra một bộ phân tích cú pháp. Nhưng tại sao không cân nhắc sử dụng trực tiếp yacc? Vì yacc vốn sinh ra để xử lý BNF. Nhưng vì IDE không phải là chất keo kết nối hiệu quả giữa các công cụ. Do đó, chúng ta phải đưa lớp kết nối xuống mức trình biên dịch C++. Nhưng đáng tiếc, khi gán quá nhiều sứ mệnh cho một công cụ đơn lẻ, dù là IDE hay trình biên dịch C++, chúng đều trở nên cồng kềnh và không còn gánh vác nổi. Hoặc ngược lại, chúng ta cố gắng thay đổi vấn đề để phù hợp với phương pháp giải quyết, thay vì điều chỉnh phương pháp giải quyết để phù hợp vấn đề.
GNU Make là điểm khởi đầu lý tưởng, nó minh họa một công cụ nhỏ gọn chuyên thực hiện nhiệm vụ kết nối các công cụ khác. Và hoàn toàn làm việc theo cách của máy tính. Giữa các công cụ, chúng giao tiếp qua dòng lệnh, mã trả về, ống dẫn (pipe) đầu vào/đầu ra. Giao diện tương tác với con người là dạng văn bản đơn giản dễ đọc. Cấu trúc phân tầng rõ ràng giúp công cụ này có thể đảm nhiệm các nhiệm vụ lớn.
Nói nhiều cũng chẳng ích lợi gì, bởi hiện tại tôi cũng không còn mấy hưng phấn để tiếp tục viết. Hãy dành thời gian còn lại tập trung giải quyết vài vấn đề đã đề cập trước đó. Những phần còn lại xin dành cho các bạn tự nghiên cứu, khám phá. Khi rời bỏ IDE, bạn sẽ tiếp cận một không gian rộng lớn hơn, tất cả các công cụ phù hợp với máy tính (có giao diện dòng lệnh) đều có thể sử dụng. Bạn không cần giới hạn ở việc người khác có cung cấp mã nguồn không, có giao diện plugin DLL tốt không nữa, mà chỉ cần quan tâm các công cụ tiền nhân tạo ra có phù hợp với nhu cầu hiện tại không. Hãy dùng đầu óc của mình để phát hiện các lối tắt, thay vì tìm kiếm tutorial từng bước một trên Google.
Vấn đề thứ nhất: Làm thế nào để quy trình biên dịch tự động nhận diện quan hệ phụ thuộc của tệp .h?
Việc tệp nguồn ngôn ngữ C phụ thuộc tệp tiêu đề .h là một thuộc tính ở cấp độ ngôn ngữ, không liên quan đến công cụ Make. Một số công cụ xây dựng (build tool), ví dụ như boost jam tôi từng dùng, có thể tự viết công cụ quét tìm quan hệ phụ thuộc này, nhưng GNU Make thì không. Tuy nhiên điều này không phải là điều xấu, nguyên tắc của một công cụ xuất sắc nên là: cố gắng hoàn thành xuất sắc một việc duy nhất.
Thực ra, việc phân tích mã nguồn để tìm ra các tệp tiêu đề phụ thuộc không hề đơn giản, ít nhất bạn phải xây dựng trình phân tích macro ngôn ngữ C/C++. Điều này vốn là một phần của trình biên dịch C/C++.
Đáng tiếc là tôi chưa từng tìm thấy tùy chọn biên dịch nào trong Visual C++ chỉ thực hiện quy trình xử lý quan hệ phụ thuộc tiêu đề. Do đó nếu bạn muốn tự động sinh quan hệ phụ thuộc trên Windows, bạn cần cài thêm gcc. MinGW cung cấp gcc là một lựa chọn tuyệt vời. Bạn hoàn toàn có thể dùng gcc để phân tích quan hệ phụ thuộc tiêu đề, sau đó dùng VC để biên dịch mã nguồn. Dù nghe có vẻ kỳ lạ nhưng tại sao lại không? Tất cả công cụ đều có thể vì ta sử dụng.
Chỉ cần thêm tham số -MM trong dòng lệnh gcc, bạn sẽ sinh ra văn bản định dạng GNU Make mô tả quan hệ phụ thuộc (bao gồm cả quan hệ trực tiếp và gián tiếp). Văn bản này xuất ra ở đầu ra tiêu chuẩn. Tuy nhiên, định dạng đầu vào có điểm khác biệt: hậu tố tệp mục tiêu là .o thay vì .obj mặc định của VC. Nhưng điều này không quan trọng