DEV Community

Cover image for Developing a PHP extension in CLion
Arnold Daniels
Arnold Daniels

Posted on • Updated on

Developing a PHP extension in CLion

Developing a PHP extension in C can be challenging compared to writing PHP code. You need to mind typing and make sure variables are initialized. There are a lot of macros and functions involved. And there is the dreaded segfault.

Working with a simple text editor can be frustrating. An IDE shows you where mistakes are made while typing. And the debugger can help to find the cause of segfaults and other issues.

If you're familiar with PHPStorm, the obvious IDE to use for extension development it CLion. Unfortunately, CLion is built around the CMake build tool, while PHP using automake.

Converting PHP to a CMake project is far from trivial. Luckily, we can make CLion behave relatively well with automake;

  • Code completion and analysis
  • Build and clean (as normal)
  • Run tests with automatic (re)build
  • Debugging

Skelton extension

The Improved PHP Library skeleton extension contains the necessary logic for editing in CLion as well as building on both *nix and Windows.

CMakeList.txt

We don't want to build the project using CMake, but we still need an add_library command for CLion to acknowledge the source files. Using ___ as the name is an indication it should be ignored (you could also use _ignore_).

Instead, we add a custom target name configure which will run phpize and ./configure for our extension.

The PHP source files need to be included. By executing php-config we can get the PHP_SOURCE directory that includes the header files.

It's common to do #include "php.h" rather than #include "main/php.h". Therefore we also include the main subdirectory. The same for Zend and TSRM.

cmake_minimum_required(VERSION 3.8)
project(skeleton C)

add_compile_definitions(HAVE_SKELETON)

set(SOURCE_FILES php_skeleton skeleton.c)

execute_process (
        COMMAND php-config --include-dir
        OUTPUT_VARIABLE PHP_SOURCE
)
string(REGEX REPLACE "\n$" "" PHP_SOURCE "${PHP_SOURCE}")

message("Using source directory: ${PHP_SOURCE}")

include_directories(${PHP_SOURCE})
include_directories(${PHP_SOURCE}/main)
include_directories(${PHP_SOURCE}/Zend)
include_directories(${PHP_SOURCE}/TSRM)
include_directories(${PROJECT_SOURCE_DIR})

add_custom_target(configure
        COMMAND phpize && ./configure
        DEPENDS ${SOURCE_FILES}
        WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})

add_library(___ EXCLUDE_FROM_ALL ${SOURCE_FILES})
Enter fullscreen mode Exit fullscreen mode

PHP versions

When building an extension, it's recommended to build and test it against multiple PHP versions. To install and use multiple PHP versions on your system you can use a tool like phpbrew.

CMake profiles

In the project settings in CLion, we create multiple CMake profiles; one per PHP version.

Create a new profile and edit the environment settings. We'll modify $PATH so the correct php, phpize and php-config executables are used.

CLion Profile env settings for PHP

Copy the existing PATH entry and paste it as custom env var. Prepend the value with the path to the bin dir of the PHP version you want to use.

PHP CLI symlink

CLion will only run configure with the selected PHP version. To run tests and debug we need to specify the path of the php cli executable. Instead of having to modify this every time, we can have autoconf create a symlink in the build subdir of this project.

AC_CONFIG_COMMANDS_POST([
  ln -s "$PHP_EXECUTABLE" build/php
])
Enter fullscreen mode Exit fullscreen mode

Build configure

Select 'configure' in build configurations with one of the PHP versions and build Ctrl+F9.

make

CLion has an automake plugin. We won't use this to build the project. The plugin runs make as command and it doesn't work with the build functionality of CLion.

Custom build target

In the project settings go to the "Custom Build Targets" tab and add a 'make' build target.

For Build click on the '...' to create an external command to the make executable. Make sure the working directory is set to the project dir.

Duplicate the external command for Clean, adding clean as argument.

Custom build configurations

make

Edit the build configurations to add a new one, choosing "Custom Build Configuration". Name the configuration "make" and select make as Target.

As executable select php located in the build directory of the project (after you've run configure). Set program arguments to include your extension. It's recommended to use -n not to ignore the default php.ini and thus not load any other extension.

-n -d "extension=modules/skeleton.so" "tests/smoke.php"
Enter fullscreen mode Exit fullscreen mode

We need to change which file is run manually for debugging.

In the "Before launch" section add Build, so make is called before running php when there are changed source files.

make build configuration for PHP in CLION

make test

PHP extension tests are written as phpt file and run with make test. Writing tests is highly recommended and required for submitting the extension to PECL.

Duplicate the make build configuration and name it "make test". Change the executable to make (instead of php) and set the program arguments to test.

The working directory needs to be set to the project directory.

Add NO_INTERACTION=1 to the environment variables to prevent the "Do you want to submit the test results?" question after running the tests.

Clean toolbar button

It may help to add Clean (Ctrl-Shift-F9) to the toolbar.

Toolbar config in CLION

Optional Makefile targets

The following is optional but will help out during development.

make info

Add a "Makefile" build configuration named "make info". Select the Makefile of the project and choose info as target.

make clean-tests

When a test fails .log, .diff, etc files are created to aid in solving the issue. These files are automatically when the test passes.

To explicitly remove the files, we need to add a custom target to the makefile by creating a Makefile.frag file and adding

clean-tests:
    rm -f tests/*.diff tests/*.exp tests/*.log tests/*.out tests/*.php tests/*.sh
Enter fullscreen mode Exit fullscreen mode

After, add a "Makefile" build configuration named "make clean-tests". Select the Makefile of the project and choose clean-tests as target.

make mrproper

make clean removes the build files, but still leaves all automake artifacts. To remove all generated files add a mrproper target to the makefile via Makefile.frag;

mrproper: clean
    rm -rf autom4te.cache build modules vendor
    rm -f acinclude.m4 aclocal.m4 config.guess config.h config.h.in config.log config.nice config.status config.sub \
        configure configure.ac install-sh libtool ltmain.sh Makefile Makefile.fragments Makefile.global \
        Makefile.objects missing mkinstalldirs run-tests.php
Enter fullscreen mode Exit fullscreen mode

Discussion (0)