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
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
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]
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.
Browse to your php-src folder and, rather than selecting the folder to open, select the compile_commands.json
file that compiledb
generated.
When CLion prompts you, choose to open it as a project.
CLion will now open the project and inform you that it successfully imported the compilation database project.
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.
I named the second tool “Clean with Make” and used make
as the program and clean
as the argument.
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.
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.
Now, click the hammer icon (🔨) or select Build -> Build Project to build PHP, or select Build -> Clean to run the make clean
command.
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.
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());
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.
Top comments (7)
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.
Thanks for this article, I would have been lost without it. My goals involved debugging using
httpd
PHP-CGI. The context was important for me; thus, a few items needed to change from above. I've created a gist here to help others in this process.Tip:
make sure m4 valid
m4 --version
If not, install via
brew install m4
orxcode-select --install
I needed to add re2c on my machine with
brew install re2c
for/.configure
to pass on my machine. FYI for anyone else.Some headers are missing, so need to execute
./scripts/dev/genfiles
beforecompiledb make
@ramsey 🔥 thanks!
Should php-src migrate to cmake? I’ve seen a repo github.com/gloob/php-cmake
I don’t know enough about cmake to know if that’s something the project would benefit from.