Compile PHP module
4 min read

Compile PHP module

Hôm rồi ngồi hì hục cài một thư viện lên máy chủ mà bị lỗi vì không tương thích với PHP API version. Sau đó mình phải ngồi dịch lại thư viện và làm một số bước khá thủ công. Mình ghi lại những điểm cần lưu ý này lại để dành cho các bạn nào cần tham khảo.

Lưu ý: bài này dành cho những bạn system admin hoặc devops. Bài viết có nhiều khái niệm nâng cao, nên các bạn nếu không hiểu thì có thể đặt câu hỏi hoặc tự đọc thêm.

Đặt vấn đề

Phần lớn khi cài các phần mở rộng của PHP lên hệ điều hành, ta thường dùng các gói chuẩn đi kèm. Cao cấp hơn chút thì dùng pecl để cài đặt một số gói mở rộng cần thiết. Tuy nhiên, có những tình huống đặc thù ta cần phải download mã nguồn của gói thư viện để dịch và cài đặt. Trong quá trình dịch và cài, đôi khi ta phát hiện ra rất nhiều lỗi kì lạ liên quan, ví dụ:

Module compiled with module API=20170718 PHP compiled with module API=20160303

Thông thường, các bạn sẽ gặp lỗi này phổ biến nhất trên các máy chủ cài đặt nhiều version PHP cùng lúc.

Ngoài ra, một hiện tượng nữa cùng thường phổ biến là trong quá trình dịch, khi chạy lệnh make test, ta thấy rất nhiều test bị skip một cách bất bình thường.

Việc gặp các issue này đều do cùng một nguyên nhân: phiên bản PHP API được sử dụng để compile cho gói mở rộng có sự khác biệt so với phiên bản PHP API mà bạn đang sử dụng.

PHP module API là gì?

Bản chất các gói PHP version x.y.z … đều được biên dịch từ mã nguồn C. Để cung cấp API ra bên ngoài cho các gói mở rộng sử dụng, thì PHP có quy định các module API chuẩn. Bạn có thể đọc thêm ở đây: http://php.net/manual/en/internals2.ze1.zendapi.php

Do đó, trong một quy trình chuẩn để compile một gói PHP mở rộng từ source, thì thường có các bước sau đây:

phpize ./configure make make test sudo make install

(Tham khảo thêm: http://php.net/manual/en/install.pecl.phpize.php)
Dòng đầu tiên với lệnh phpize rất quan trọng. Nó giúp chuẩn bị môi trường biên dịch cho gói mở rộng dựa theo phiên bản PHP mặc định đang dùng của hệ điều hành.

Tại sao có hiện tượng khác biệt giữa PHP module version của gói đang dịch và của hệ điều hành

Thường hiện tượng này sẽ xảy ra khi:

  • Bạn upgrade / downgrade php version mà không thay đổi file phpize version tương ứng.
  • Chuyển qua lại giữa các version php

Thường thường, phpize sẽ được cài vào thư mục /usr/bin. Trên một hệ điều hành có nhiều phiên bản php, bạn sẽ nhìn thấy folder này chứa các file phpize như sau:

Ngoài ra, còn một thư mục quan trọng nữa là /usr/bin/php-config. Thư mục này cũng được sử dụng để chuẩn bị môi trường biên dịch cho extension.

Chính việc sử dụng không đúng phiên bản phpize và php-config trong quá trình biên dịch sẽ làm cho kết quả cuối cùng ta có một phiên bản của extension không tương thích với PHP module API đang dùng.

Cách fix vấn đề rất đơn giản, chỉ cần thông qua 2 bước:

  • Xác định ta cần dùng phpize và folder php-config của php version nào
  • Sau đó, backup phpize và php-config folder cũ, rồi copy file phpize và php-config folder tương ứng đè lên. Cuối cùng chỉ cần làm theo các bước biên dịch như bình thường.

Làm sao ta xác định được cần dùng bản phpize và php-config folder nào?

Rất đơn giản. Bạn chỉ cần xác định php version đang chạy bằng lệnh php -v. Xem version của php và chọn phpize / php-config folder tương ứng.

Khoan! còn thiếu gì đó nhỉ?

Bạn nên nhớ php có thể chạy ở mode cli (console) và chạy tích hợp với web server (phổ biến nhất là bằng fpm). Do đó, bạn phải đảm bảo nhất quán là php version của php-fpm cũng sẽ cần được install extension này (nếu web có sử dụng).

Đơn giản vậy thôi !

Hẹn gặp lại trong bài sau.