Tips & Tricks: Develop OpenJDK in CLion with Pleasure
You’ve probably heard that dogfooding at JetBrains is a mission-critical part of our development process. You may also know that we build our own JetBrains Runtime to provide a runtime environment for running IntelliJ-based products. It’s based on OpenJDK, and so, obviously, it’s a great opportunity for dogfooding in CLion.
Besides, there is a huge community contributing to OpenJDK that often asks about tips & tricks for dealing with the native part of the OpenJDK project in CLion. There are already several tried and tested collections of tips & tricks from the community leads. In this blog post, we’d like to share our own tips & tricks from our own experience of developing OpenJDK in CLion.
- Step 1: Get the source code and the tooling ready
- Step 2: Open project in CLion
- Step 3: Generate Run Configurations and Build Targets
- Step 4: A few debugging tips
Step 1: Get the source code and the tooling ready
You can get the latest OpenJDK sources either from the official mercurial repo (hg clone https://hg.openjdk.java.net/jdk/jdk
) or from the GitHub mirror (might be faster). Please carefully read how to prepare the local environment.
Download either the latest version of CLion from our site or check out the recent CLion 2020.1 EAP build (this one offers a better debugging experience on Windows).
Step 2: Open project in CLion
While there is ongoing work to natively support Makefile projects in CLion, for this instruction we’ll be using an OpenJDK compilation database to work with the project in CLion.
- Read how to create the compilation database for the OpenJDK native code
${source_root}/doc/ide.md
. - Select the build target. If you want to debug your build, the best option is to do
configure --with-debug-level=fastdebug
. - Run
make compile-commands
to generate the project for all the source code. You can also runmake compile-commands-hotspot
to generate the project for HotSpot only. - Make sure you now have a
compile_commands.json
file in the${source_root}/build/<target>/
directory. - For some modules, precompiled headers are used. Because of this we suggest building OpenJDK before generating the project model. To build binaries, just call
make
. - Refer to CLion’s online help on compilation databases to understand what they are and the possible ways you can generate one.
- On Windows, there are a few issues with the OpenJDK compilation database (some are CLion issues and we plan to address them in the future, some are just because of an incorrect compilation database on the OpenJDK side, but we can try and workaround them in CLion): CPP-19223, CPP-19225, CPP-19224. We have this short java program to fix the issues. There is no need to compile it; just do
java <path/to/FixCompileCommands.java> <absolute/path/to/generated/compile_commands.json>
. The original file will be saved ascompile_commands.json.old
. - Make sure that you have configured toolchains in CLion. On Windows, configure and set Visual Studio as the default (make it the first in the list):
- Now open the generated
compile_commands.json
as a project in CLion. It will take approximately 20 seconds to load on an average machine. - By default, the project root is set to the directory containing the compilation database file. So change the project root directory to
${source_root}
.
Now the project is ready in CLion!
Step 3: Generate Run Configurations and Build Targets
The compilation database itself lacks the data required for building, running, and debugging an application. However, you can set up the workflow by adding custom build targets for your compilation database project and then creating custom Run/Debug configurations for these targets.
Custom build targets for OpenJDK
To configure custom build targets, go to Settings/Preferences | Build, Execution, Deployment | Custom Build Targets:
- Use the default toolchain on Linux and macOS. On Windows, use the Visual Studio toolchain.
- Configure the new external tools for the build and clean steps:
- On Linux and macOS: set a name and description, select
make
as the program, and specify the make arguments that should be used to build your image. In our case, the only argument is the make configuration:CONF=macosx-x86_64-server-fastdebug
. Set${source_root}
as the Working Directory: - On Windows, Unix build tools are still an essential part of the build process, so we run build and clean via Cygwin (or you can do it via WSL). To do this, set the program field to something like
C:\cygwin64\bin\bash
and arguments as--login -c "cd /cygdrive/c/${source_root}; make CONF=windows-x86_64-server-fastdebug"
for build and--login -c "cd /cygdrive/c/${source_root}; make clean CONF=windows-x86_64-server-fastdebug"
for clean:
Custom Run/Debug configurations
Go to Run | Edit Configurations and start a new Run and Debug configuration based on the Custom Build Application template.
- Select the custom target you created earlier as Target.
- Set Executable to the
java
binary built as part of an image (in our case it is${source_root}/build/macosx-x86_64-server-fastdebug/jdk/bin/java
) - Set Program Arguments.
- The JDK build system is smart, and incremental compilation is pretty fast. However, if you don’t want to rebuild OpenJDK before each run or debug, you can disable build step in the Before launch section of the run configuration settings:
We are almost there!
Step 4: A few debugging tips
We debug with the LLDB debugger. This includes Windows, where CLion comes with the bundled LLDB-based debugger for the Microsoft Visual C++ toolchain.
- On Linux and macOS, create a custom .lldbinit file in the same directory where the compile_commands.json file was generated.
- Add
br set -n main -o true -G true -C "pro hand -p true -s false SIGSEGV SIGBUS"
to this file to suppress signal handling. - Don’t forget to explicitly allow LLDB to use the config file from the project directory.
- Add
- Some debugger features are not available (that is, they do not automatically show all local variables for the frame) for the binary built with
fastdebug
configuration. You still can watch any specific variable manually. If you need to debug the binary without any optimizations, switch to theslowdebug
configuration. - Set a breakpoint (for example, on a line of the
Arguments::init_system_properties
function) and click the debug button. - CLion should stop on a breakpoint in your code:
That’s it! Do you have any questions or feedback? Try it out and tell us what you think in the comments below.
Your CLion team
JetBrains
The Drive to Develop