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.
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
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
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 -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]
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
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
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.
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
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.