When building a browser there are many tasks, both large and small, that have to be done. One of these tasks is to specify how to build the application. In a Chromium-based browser, such as Vivaldi, this is done by using a tool developed by Chromium called GN.
When we update the configuration of related GN files in the Chromium code base – so that the application components can connect to the code Vivaldi adds to the application – some “merge conflicts” occur. As part of working around this problem, we added various extensions to the GN language and decided to share them with the community.
Other projects, in particular, those based on Chromium, can benefit from using these extensions and this is the reason we’re making them available in a GitHub repository as a fork of the GN project.
Why we need extensions for GN
GN is a compiler that reads the project’s configuration files and outputs files used by the “Ninja” build tool, which is then used to build the application.
When we specify the GN files for Vivaldi, we can’t just write those files for Vivaldi source code tasks, we also have to update the configuration of related GN files in the Chromium code base so that the application components that those files specify can connect to the code Vivaldi adds to the application.
This may sound straightforward, and in some ways it is.
The problem with updating or “patching” the files in Chromium comes later when we update our code base with new code from the Chromium project. Frequently, the Chromium developers will have made modifications not just to the same files we updated, but close to where we added our changes, causing a “merge conflict”.
Currently, there are dozens of these conflicts each time we upgrade, but in the past, we’ve had hundreds. In such cases, we have to fix the file before we can continue updating the code.
In order to avoid these conflicts as much as possible, we have moved many of our patches out of the Chromium code, and into our own code base.
With respect to the GN files, this presents a bit of a problem, as the GN tool does not permit this. You can put all new files in target files located in your own code base, but they still have to be hooked into the Chromium GN files.
Vivaldi adds extensions to GN
To work around this and other issues we have modified the GN tool used by Vivaldi, adding various extensions to the GN language. This has reduced the maintenance overhead significantly.
With the help of these extensions, we can move most of our relatively simple – and frequent – modifications of the project files into our own source code project files, and even move entire functions we have added to the code into our own code base.
We’re confident that other projects, in particular, other projects based on Chromium, can benefit from using these extensions.
Earlier this year we asked the Chromium GN team to include them in their version. The GN developers decided not to accept most of the extensions since they felt that these extensions did not fit with their vision of how GN should work.
This is the reason we’re making these extensions available in a GitHub repository as a fork of the GN project.
Find out more about Vivaldi’s extensions to GN
So what exactly are the extensions that you can get there? Here’s the current list:
- An extension to the target label system   used to specify source files and dependencies, allowing vendor specific GN targets to be specified as //vendor/foo. Other projects have used various other ways to specify such labels, e.g. “$vendor/foo” where the variable “vendor” is an absolute file path that has to be calculated by a script before generating the project. In our opinion, this is a less than optimal way of specifying such labels.
- Functions to update   variables in targets. The GN language specifies targets as a set of variables specifying the source files, target dependencies, scripts to be run, input and output file names, etc., along with functions to calculate these values. In order to move our changes out of the Chromium GN files, we added a couple of functions that allow us to update the variables in these targets once the original code has been run, effectively patching the target. This allows us, for example, to add source files that need to be compiled alongside the other files in that target, or add extra dependencies, without actually updating the original GN file.
- Specify overrides of default variables. GN has several ways to specify configuration variables, such as what kind of features to enable in a given version of the application. One is the default configuration stored in the GN files, another is to specify variables on the command line when generating the project, a third is to specify them in one of the configuration files. The second option requires the developer to choose the values manually, and the third does not allow calculation of the value based on, for example, the target operating system or processor architecture. In Vivaldi’s GN variant, we added a function that allows us to specify variable value overrides after calculating them based on other enabled features, operating system, CPU, etc. This allows us, for example, to enable or disable features for the Mac version, without requiring the developer to remember “Oh, have to add that value to the command line” when setting up the project.
- Allow BUILDCONFIG.gn files to inline other files. The BUILDCONFIG.gn specifies a lot of the internal defaults for a given project, and in the case of Chromium, this file is fairly big. By default, GN will not allow this file to import other files so that it can make its own changes to those internal defaults, without completely copying the entire file, or editing the original file and using it instead (which, as mentioned above, causes maintenance problems). In Vivaldi’s GN we have added an override when this particular file is being processed, allowing imports of other files in a way that does not cause the problems that prevented imports before.
Main photo by Ant Rozetsky on Unsplash.com.