DEV Community

Cover image for Using CLion with php-src
Ben Ramsey
Ben Ramsey

Posted on

Using CLion with php-src

I’ve cloned and built php-src numerous times over the years, on a variety of platforms, but I’ve never worked with it in an IDE. A long-time Vim user, I’ve only begun using PhpStorm over the last year and a half, after seeing how IntelliJ helped me easily navigate an open source Java project. So, in setting up php-src for release management tasks, I wanted to give CLion a try.

Getting php-src ready for CLion

When opening existing source code or cloning a repo with CLion, it assumes the project already supports CMake tooling for builds. For someone new to C and using a project that doesn’t use CMake, this can be confusing and frustrating. Since php-src isn’t a CMake project, CLion will display warnings at the top of every open file, saying that a “CMake project is not loaded,” giving you the option to select or generate a CMakeLists.txt file. You can try to do this for php-src, but there’s a better way.

CLion also supports JSON compilation databases. To generate one and have CLion recognize php-src as a compilation database project, you’ll need to do the following before opening php-src in CLion. If you’ve already opened it in CLion, that’s okay. Delete the .idea/ folder that CLion creates, and then do the following. (I could not figure out a way to make CLion recognize the compilation database if I had already opened the project in CLion. It seems the compilation database must exist the first time you open the project in order for CLion to recognize it.)

You’ll need the compiledb Python tool to generate the compilation database. It wraps the make command, so when you run it with make, it captures all the sources and creates a compile_commands.json file. Then, when you open the project in CLion for the first time, it will recognize your project as a compilation database project.

pip install compiledb

git clone https://github.com/php/php-src.git ~/repos/php/php-src
cd ~/repos/php/php-src
./buildconf
./configure \
    --prefix=$HOME/builds/php/8.1.0-dev \
    --disable-all \
    --disable-cgi \
    --enable-debug \
    --enable-zts

compiledb make
Enter fullscreen mode Exit fullscreen mode

As you can see here, I use compiledb to call make. In this way, compiledb can learn about all the sources for your build.

You may also pass -jN to make, where N is the number of CPU cores your system has available. This will greatly speed up compilation.

You can run nproc to find out how many cores you have. On my system, I have 12 cores, so I run the command like this:

compiledb make -j12
Enter fullscreen mode Exit fullscreen mode

In my example, I pass --prefix to configure, but this isn’t necessary since I’m not going to run make install. Once make has finished building PHP, you can find the newly-built PHP CLI at sapi/cli/php.

$ ./sapi/cli/php -v
PHP 8.1.0-dev (cli) (built: May  6 2021 18:27:37) (ZTS DEBUG)
Copyright (c) The PHP Group
Zend Engine v4.1.0-dev, Copyright (c) Zend Technologies

$ ./sapi/cli/php -m
[PHP Modules]
Core
date
hash
json
pcre
Reflection
SPL
standard

[Zend Modules]
Enter fullscreen mode Exit fullscreen mode

Setting up CLion to build and run PHP

Now that php-src has a compilation database (which needs to be updated each time you change your build with configure or if you add new sources that get included in make), you can open it in CLion.

Launch CLion to get to the welcome screen and choose to open a project from existing sources.

CLion welcome screen

Browse to your php-src folder and, rather than selecting the folder to open, select the compile_commands.json file that compiledb generated.

File selection dialog highlighting compile_commands.json

When CLion prompts you, choose to open it as a project.

"Open as Project" dialog

CLion will now open the project and inform you that it successfully imported the compilation database project.

Compilation database project successfully imported

With CLion open, you’ll now create custom build targets for make and make clean.

Open CLion Preferences and go to Build, Execution, Deployment -> Custom Build Targets. Create a new build target, named something like “Build PHP.” Then, next to the empty Build and Clean fields, click the more button (with three dots). This will open an External Tools window. Use the +-button here to create two external tools.

I named the first one “Build with Make.” The program is make and I added -j12 to the arguments for a faster build (see earlier). You might also consider using compiledb as the program, with make -j12 as the arguments.

"Build with Make" external tool

I named the second tool “Clean with Make” and used make as the program and clean as the argument.

"Clean with Make" external tool

Now, you can click OK to close these windows and the External Tools window, and select the proper tools to use with your Build PHP target.

"Build PHP" build target with external tools selected

Finally, you’ll want to create a custom run/debug configuration. To do this, go to Run -> Edit Configurations….

Use the +-button to create a new configuration and choose Custom Build Application from the menu that appears. I named my configuration “Build PHP” and I chose my “Build PHP” target (created earlier) from the Target dropdown list. For the executable, I entered the path to the PHP CLI built by this project (remember, it’s at sapi/cli/php). Last, I checked “Redirect input from” and entered the JetBrains variable $FilePrompt$. In this way, whenever you chose to run PHP from within CLion, it will prompt you with a file dialog to execute through the PHP interpreter. This lets you select a PHP script to run and test/debug whatever feature you’re working on.

"Build PHP" run/debug configuration

Now, click the hammer icon (🔨) or select Build -> Build Project to build PHP, or select Build -> Clean to run the make clean command.

Output after running "Build with Make"

If you click the play icon (▶️) or choose Run -> Run ‘Build PHP’, it will prompt you to select a file and run that file as a PHP script. In the following, I’ve selected one of the .phpt tests to execute this way.

Using the file selection dialog to select a PHPT file to run

Output after running the PHPT file

Step debugging through php-src

One of the primary reasons I wanted to use an IDE to work with php-src is for the debugging tools. With everything set up as described earlier, I’m able to run a PHP script and break on breakpoints in the C source code.

As an example, I created a PHP script named date-debug.php and added the following code to it.

<?php
echo date('Y-m-d H:i:s', time());
Enter fullscreen mode Exit fullscreen mode

Then, I opened ext/date/php_date.c and placed a breakpoint in the php_date() function. You can see the breakpoint in the following screenshot. I placed it right after the ZEND_PARSE_PARAMETERS block.

When you click the debug icon (🪲) or choose Run -> Debug ‘Build PHP’, CLion will prompt you to select a file, just like it does when when you click the play icon, as described earlier. When I choose the date-debug.php file, it begins executing it and then stops at the breakpoint in the C code, which happens to be the code called when using the PHP date() function. As you can see, I’m now able to examine the memory and variables in this function, including the zvals.

Inspecting variables at a breakpoint in the C source code for PHP

Top comments (6)

Collapse
 
aschwin profile image
Aschwin Wesselius

This looks great! I hope other people find this interesting too so PHP-extension development can finally take off amongst people who would hesitate tinkering with plain C code.

I mean, understanding the PHP-extension mechanism from the code itself, or from a tutorial or book is one thing. But stepping through it with an IDE speeds up the understanding a lot.

Collapse
 
eaglewu profile image
Di Wu

Tip:
make sure m4 valid m4 --version
If not, install via brew install m4 or xcode-select --install

Collapse
 
mglaman profile image
Matt Glaman

I needed to add re2c on my machine with brew install re2c for /.configure to pass on my machine. FYI for anyone else.

Collapse
 
oandreyev profile image
Oleg Andreyev

Some headers are missing, so need to execute ./scripts/dev/genfiles before compiledb make

Collapse
 
oandreyev profile image
Oleg Andreyev

@ramsey 🔥 thanks!
Should php-src migrate to cmake? I’ve seen a repo github.com/gloob/php-cmake

Collapse
 
ramsey profile image
Ben Ramsey

I don’t know enough about cmake to know if that’s something the project would benefit from.