Các nhà phát triển tranh luận về Make và hệ thống build hiện đại khi hướng dẫn biên dịch C gây ra cuộc thảo luận

Nhóm biên tập BigGo
Các nhà phát triển tranh luận về Make và hệ thống build hiện đại khi hướng dẫn biên dịch C gây ra cuộc thảo luận

Một hướng dẫn gần đây về biên dịch chương trình C sử dụng Make đã khơi dậy những cuộc thảo luận sôi nổi trong cộng đồng nhà phát triển về hệ thống build, quản lý dependency và tính liên quan đang diễn ra của các công cụ có tuổi đời hàng thập kỷ trong phát triển phần mềm hiện đại.

Biến môi trường và cờ trình biên dịch tạo ra sự nhầm lẫn

Cộng đồng đã nêu bật sự nhầm lẫn đáng kể xung quanh các biến môi trường của Make, đặc biệt là CPPFLAGS và CXXFLAGS. Nhiều nhà phát triển nhầm tưởng rằng chúng phục vụ các mục đích tương tự, nhưng thực tế chúng khá khác nhau. CPPFLAGS xử lý các tùy chọn C preprocessor bất kể ngôn ngữ nào, trong khi CXXFLAGS nhắm mục tiêu cụ thể vào biên dịch C++. Sự phân biệt này trở nên quan trọng khi khắc phục sự cố biên dịch, đặc biệt trên macOS nơi các đường dẫn dependency thường yêu cầu chỉ định thủ công.

Cuộc thảo luận cũng tiết lộ rằng thứ tự cờ linker có ý nghĩa quan trọng trong các tình huống static linking, mặc dù yêu cầu này biến mất với dynamic linking. Sắc thái kỹ thuật này đã khiến nhiều nhà phát triển bất ngờ, dẫn đến các lỗi build bí ẩn dường như hoạt động trên một số hệ thống nhưng không hoạt động trên các hệ thống khác.

Lưu ý: C preprocessor (cpp) là một công cụ xử lý mã nguồn trước khi biên dịch, xử lý các tác vụ như bao gồm các tệp header và mở rộng macro.

Các biến môi trường chính của Make:

  • CPPFLAGS: Cờ tiền xử lý C (dùng cho vị trí file header)
  • CXXFLAGS: Cờ trình biên dịch C++
  • LDFLAGS: Cờ linker đặt trước các file object
  • LDLIBS: Cờ thư viện (như -lssl -ldl) đặt sau các file object

Make như giao diện phổ quát đang được ưa chuộng

Một xu hướng thú vị đã xuất hiện khi các nhà phát triển sử dụng Make như một giao diện tiêu chuẩn hóa trên các ngôn ngữ lập trình và dự án khác nhau. Thay vì nhớ các lệnh build cụ thể cho từng ngôn ngữ khác nhau, nhiều nhóm hiện triển khai các target Make nhất quán như make format, make lint, và make build bất kể họ đang làm việc với Go, Rust, Python, hay các ngôn ngữ khác.

Cách tiếp cận này giải quyết một sự bực bội phổ biến khi các dự án di chuyển giữa các hệ thống build khác nhau theo thời gian. Trong khi các công cụ cơ bản có thể thay đổi từ package manager này sang package manager khác, các lệnh Make cấp cao vẫn không đổi, giảm gánh nặng nhận thức cho các nhà phát triển chuyển đổi giữa các dự án.

Các Make Target Phổ Biến Trong Các Ngôn Ngữ Lập Trình:

  • make format: Định dạng code
  • make lint: Phân tích/kiểm tra code
  • make build: Build dự án
  • make docker_build: Build Docker container
  • make docker_run: Chạy Docker container
  • make install_deps: Cài đặt các dependency

Quản lý dependency vẫn là gót chân Achilles của C

Cuộc thảo luận cộng đồng đã củng cố rằng việc thiếu dependency manager tích hợp sẵn của C tiếp tục là một điểm đau lớn. Trong khi một số lập luận rằng các system package manager như apt hoặc homebrew đóng vai trò này, những người khác chỉ ra các giải pháp mới hơn như Conan và vcpkg như những lựa chọn thay thế đang nổi lên.

Tuy nhiên, nhiều nhà phát triển C có kinh nghiệm thực sự xem điều này như một tính năng hơn là một lỗi. Các dự án phức tạp thường liên quan đến nhiều ngôn ngữ lập trình, khiến các dependency manager cụ thể cho ngôn ngữ có khả năng gây hại cho quá trình build tổng thể. Cách tiếp cận quản lý dependency thủ công, mặc dù tốn nhiều công sức hơn ở phía trước, cung cấp kiểm soát và minh bạch tốt hơn.

Các Giải Pháp Quản Lý Phụ Thuộc C:

  • Trình Quản Lý Gói Hệ Thống: apt, homebrew, dnf, pacman
  • Công Cụ Chuyên Dụng Cho C: Conan, vcpkg
  • Quản Lý Thủ Công: Phương pháp truyền thống với việc cài đặt thư viện thủ công
  • Bản Dựng Container Hóa: Đóng gói phụ thuộc dựa trên Docker

Các hệ thống build thay thế thách thức sự thống trị của Make

Cuộc thảo luận đã tiết lộ sự quan tâm ngày càng tăng đối với các lựa chọn thay thế cho Make truyền thống. Một số nhà phát triển ủng hộ hệ thống mk của Plan 9, ca ngợi cú pháp sạch hơn và các biến tự động mô tả hơn. Những người khác gợi ý rằng các công cụ hiện đại như CMake, mặc dù có độ phức tạp riêng, cung cấp hỗ trợ đa nền tảng và xử lý dependency tốt hơn.

Không ai khác biết nó hoạt động như thế nào, đó là lý do tại sao mọi configure script đều kiểm tra trình biên dịch fortran hoạt động.

Tình cảm này về autotools phản ánh sự bực bội rộng hơn với các hệ thống build cũ đã tích lũy hàng thập kỷ phức tạp và các trường hợp ngoại lệ.

Docker nổi lên như giải pháp môi trường build

Một giải pháp thực tế đang được ưa chuộng liên quan đến việc sử dụng container Docker để cung cấp môi trường build nhất quán. Cách tiếp cận này gói gọn các trình biên dịch và dependency vào các container có thể tái tạo, loại bỏ vấn đề hoạt động trên máy của tôi gây khó khăn cho việc biên dịch C trên các hệ thống khác nhau.

Tuy nhiên, chiến lược này gặp phải hạn chế với static linking, đặc biệt trên các hệ thống sử dụng glibc, không hỗ trợ đầy đủ biên dịch tĩnh. Ràng buộc kỹ thuật này có nghĩa là các build được container hóa không phải lúc nào cũng tạo ra các tệp nhị phân thực sự di động.

Cuộc tranh luận đang diễn ra phản ánh một căng thẳng rộng hơn trong phát triển phần mềm giữa việc duy trì khả năng tương thích với các công cụ đã được thiết lập và việc chấp nhận các lựa chọn thay thế hiện đại hứa hẹn trải nghiệm nhà phát triển tốt hơn. Trong khi Make đang tiến gần đến kỷ niệm 50 năm, cộng đồng vẫn chia rẽ về việc liệu tuổi thọ của nó có đại diện cho độ tin cậy đã được chứng minh hay nợ kỹ thuật tích lũy.

Tham khảo: Using make to compile C programs (for non-C-programmers)