最近有人在windows 7下的webkit编译不过去,问我该怎么解决。我看了一下,主要是SVGAnimationElement.cpp等文件编译不过去,这里面使用了开启svg后的一些枚举变量,但webkit在编译时生成的WebKitBuild/include/WebCore/CSSPropertyNames.h文件里面并没有生成这些枚举变量,我检查一些编译选项,配置都是OK的,我又看了一下webkit的编译规则,发现CSSPropertyNames.h的生成是依赖CSSPropertyNames.in等文件。解决方法也简单:将CSSPropertyNames.in等文件里面加上一行后再删除,再编译就OK了。为什么这样就可以了呢?愿意是windows下的makefile的编译依赖并不像linux下那么可靠,有时候windows版的makefile工具在编译出错了也更新了文件的修改时间,导致下次makefile再检查时认为文件没改变,从而跳过去了,上面所说的CSSPropertyNames.in就是这种情况。前面我的blog里面也写了一下webki编译方面的文章,网上也有一些类似的文章,也有很多网友在webkit编译不过时发帖询问,所以我觉得很多人对webkit是如何编译的并不是太清楚,导致编译出错了不知道原因,自然也不知道如何去解决这个问题。久而久之,越来越多的人就会发现编译webkit都是一个问题,更不用说去研究webkit了。为了帮助这些人克服对webkit编译的恐惧,我这几天详细看了一下webkit在windows下的编译规则,写也这篇类似于总结的文章。
1. 目录划分
在webkit源码的根目录下,有Makefile,CMakeLists.txt,android.mk,WebKit.pro等文件与编译有关,其中makefile主要用于linux环境下,windows上虽然用了cygwin,却并没有使用这个makefile去编译;CMakeLists.txt主要是用于cmake环境下,这是一个跨平台的编译环境,但我发现在windows下使用cmake编译的人并不多,这可能主要是因为webkit官网介绍的主要是cgywin+vs的编译方式导致的;WebKit.pro是qt环境下的编译规则,qt自己定了一套编译规则,做了一个类似于makefile的工具qmake,是跨平台的,但是得下一套qt的编译环境或sdk,所以这个也主要是qt的人在维护,不过qt版的webkit发展还是不错的;android.mk是android下webkit的编译规则。这篇文件要介绍的windows编译规则在根目录并没有包含,而是在下面的子目录下实现的,原因可能是这套规则(cygwin+vs)只适合于windows平台,不是一个common的东西,所以不能放在根目录下,cygwin+vs这套环境主要是apple的人在维护,safari的windows版本应该也是使用这套环境编译出来的。顺便提一下,chrome下的编译规则后缀是gypi,例如webcore目录下的WebCore.gypi文件。
webkit主要由3部分组成:JavaScriptCore,WebCore,WebKit。JavaScriptCore下主要是浏览器使用的javascript引擎代码,当使用v8引擎时,这个目录是不参加编译的;WebCore下的代码是浏览器的核心了,包括网页解析,layout,render等,dom规范和css规范的也是在这里面实现的,如果像知道浏览器里面的window对象是如何实现的,可以去WebCore/dom下看看,WebCore下与平台相关的是针对不同平台有不同的目录,编译依赖也是不一样的;WebKit下是提供给浏览器外壳的接口的实现代码。最终,JavaScriptCore被编译成了JavaScriptCore.dll,webcore和webkit目录被编译成了webkit.dll。JavaScriptCore.dll以dll export的方式导出了函数供webcore和webkit使用,webkit.dll则是以COM的方式提供接口给浏览器外壳(例如safari.exe)使用。如果你对比一下webkit目录在mac和windows上的实现,就会发现Object-C和COM的概念有很多方面是相似,只不过Object-C在语言级别将COM思想的一些复杂实现简化了。
在webkit的其他目录,与编译相关的目录还有WebKitLibraries,WebKitTools等。WebKitLibraries里面放着编译依赖的头文件和lib,例如icu,libxml,sqlite的头文件和lib,当我们执行update-webkit命令时,有一步就是从apple官网下载WebKitSupportLibrary.zip,然后解压到WebKitLibraries目录下;WebKitTools主要放着一些工具和例子,与编译相关的主要放着WebKitTools/Scripts目录下,例如update-webkit和build-webkit都是放在这下面,这个目录下perl脚本居多,bat(cmd)和py占少数。这种多种语言混在一起在编译环境里面是很常见的,从中我们可以学到一点的是用最适合的工具和语言做你想做的事情,没必要去争谁好谁坏,每个工具和语言都有自己的优点和弱点,用刀就要用刀刃。工具始终是工具,总有被淘汰的时候和地方,我们真正要关注的是我们的目标。
在windows下,很多人第一次编译webkit都是在cygwin的命令行里面执行build-webkit开始的,build-webkit其实也是调用vs的devenv.exe编译的,只不过它是在命令行编译,而更多人在后期都会使用vs ide去编译,因为比较直观和熟悉。当vs ide有一个问题是有点占内存,它的智能提示会经常扫描文件,弄得cpu占有率很高,最终智能提示生成的ncb文件也很大,不过这个有一个好处是调试的时候比较好找对应的函数实现(如果你的机器够强劲,装上Visual Assist X插件会更好)。vs工程在各个目录的位置如下:
JavaScriptCore:D:/tools/cygwin/home/xufan/WebKit/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj,D:/tools/cygwin/home/xufan/WebKit/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj等
WebCore:D:/tools/cygwin/home/xufan/WebKit/WebCore/WebCore.vcproj下的WebCore.vcproj等
Webkit:D:/tools/cygwin/home/xufan/WebKit/WebKit/win/WebKit.vcproj下的WebKit.vcproj等
整个webkit solution的文件是D:/tools/cygwin/home/xufan/WebKit/WebKit/win/WebKit.vcproj/WebKit.sln,双击可以用vs ide打开。
下面将从webkit的目录挑出一些代表性的编译规则进行讨论:
2. WebKitTools/Scripts目录
首先从update-webkit脚本说起,这个脚本主要是调用svn update(或git)去更新代码(80,81行),然后调用update-webkit-auxiliary-libs,update-webkit-auxiliary-libs通过curl下载WebKitSupportLibrary.zip(92行),最后解压到WebKitLibraries目录下(96行,116行)。
接下来看build-webkit脚本,build-webkit脚本的前344行主要是将命令行参数转换为perl里面的变量,289行到315行可以看到build-webkit支持的参数:
Usage: $programName [options] [options to pass to build system]
--help Show this help message
--clean Cleanup the build directory
--debug Compile in debug mode
--wincairo Build using Cairo (rather than CoreGraphics) on Windows
--chromium Build the Chromium port on Mac/Win/Linux
--gtk Build the GTK+ port
--qt Build the Qt port
--efl Build the EFL port
--inspector-frontend Copy changes to the inspector front-end files to the build directory
--install-headers= Set installation path for the headers (Qt only)
--install-libs= Set installation path for the libraries (Qt only)
--v8 Use V8 as JavaScript engine (Qt only)
--prefix= Set installation prefix to the given path (Gtk/Efl only)
--makeargs= Optional Makefile flags
--minimal No optional features, unless explicitly enabled.
build-webkit接下来调用的很多函数都是在webkitdirs.pm里面定义的(build-webkit的第40行:use webkitdirs),例如productDir(),这个是webkit输出结果的目录,从productDir的实现来看,输出目录主要是由WEBKITOUTPUTDIR这个环境变量决定的(webkitdirs.pm的119行),如果不存在则用根目录下的WebKitBuild目录(154行:$baseProductDir = "$sourceDir/WebKitBuild";)。360行到500行都是做一些检查工作,开始编译是从500行到551行,如下:
- # Build, and abort if the build fails.
- for my $dir (@projects) {
- chdir $dir or die;
- my $result = 0;
- # For Gtk and Qt the WebKit project builds all others
- if ((isGtk() || isQt()) && $dir ne "WebKit") {
- chdir ".." or die;
- next;
- }
- if (isGtk()) {
- $result = buildGtkProject($dir, $clean, @options);
- } elsif (isQt()) {
- $result = buildQMakeQtProject($dir, $clean, @options);
- } elsif (isAppleMacWebKit()) {
- $dir = "MiniBrowser" if $dir eq "WebKitTools/MiniBrowser";
- my @local_options = @options;
- push @local_options, XcodeCoverageSupportOptions() if $coverageSupport && $dir ne "ANGLE";
- $result = buildXCodeProject($dir, $clean, @local_options, @ARGV);
- } elsif (isAppleWinWebKit()) {
- if ($dir eq "WebKit") {
- $result = buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean);
- }
- }
- # Various build* calls above may change the CWD.
- chdirWebKit();
- if (exitStatus($result)) {
- my $scriptDir = relativeScriptsDir();
- if (usingVisualStudioExpress()) {
- # Visual Studio Express is so lame it can't stdout build failures.
- # So we find its logs and dump them to the console ourselves.
- system(File::Spec->catfile($scriptDir, "print-vse-failure-logs"));
- }
- if (isAppleWinWebKit()) {
- print "/n/n===== BUILD FAILED ======/n/n";
- print "Please ensure you have run $scriptDir/update-webkit to install dependencies./n/n";
- my $baseProductDir = baseProductDir();
- print "You can view build errors by checking the BuildLog.htm files located at:/n$baseProductDir/obj//./n";
- }
- exit exitStatus($result);
- }
- }
在cygwin+vs的环境下执行的是:buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean),buildVisualStudioProject的代码如下(在webkitdirs.pm的1205行):
- sub buildVisualStudioProject
- {
- my ($project, $clean) = @_;
- setupCygwinEnv();
- my $config = configurationForVisualStudio();
- dieIfWindowsPlatformSDKNotInstalled() if $willUseVCExpressWhenBuilding;
- chomp($project = `cygpath -w "$project"`) if isCygwin();
- my $action = "/build";
- if ($clean) {
- $action = "/clean";
- }
- my @command = ($vcBuildPath, $project, $action, $config);
- print join(" ", @command), "/n";
- return system @command;
- }
setupCygwinEnv主要是通过环境变量去查找vs的安装位置,然后调用pdevenv脚本(1094行)去根据vs的版本调用不同的脚本去设置vs编译环境。vsvars32.bat和devenv.com应该大家都比较熟(不知道的可以看看开始菜单里面的Visual Studio 2005 Command Prompt快捷方式的指向),调用它们就是在pdevenv脚本里面做的。
最终调用vs的脚本展开后的形式可以看cygwin的命令行输出(见上面的my @command = ($vcBuildPath, $project, $action, $config);及其下面的一行),我这边是:
/home/xufan/Webkit/WebKitTools/Scripts/pdevenv win/WebKit.vcproj/WebKit.sln /build Debug_Cairo_CFLite
调用devenv.exe之后,编译规则就完全是vs的规则了,入口是WebKit/win/WebKit.vcproj/WebKit.sln,比较重要的工程是上面所说的JavaScriptCore.vcproj,WebCore.vcproj和WebKit.vcproj这几个工程了。
今天就先到这了,明天接着写这些比较重要的vs工程,重点包括js dom的对象(例如window对象)粘合(glue)到javascriptCore的代码是如何自动生成的,如果根据css关键字生成代码,webcore下面文件的编译顺序和规则等。