最近有人在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.<br />for my $dir (@projects) {<br /> chdir $dir or die;<br /> my $result = 0;<br /> # For Gtk and Qt the WebKit project builds all others<br /> if ((isGtk() || isQt()) && $dir ne "WebKit") {<br /> chdir ".." or die;<br /> next;<br /> }<br /> if (isGtk()) {<br /> $result = buildGtkProject($dir, $clean, @options);<br /> } elsif (isQt()) {<br /> $result = buildQMakeQtProject($dir, $clean, @options);<br /> } elsif (isAppleMacWebKit()) {<br /> $dir = "MiniBrowser" if $dir eq "WebKitTools/MiniBrowser";<br /> my @local_options = @options;<br /> push @local_options, XcodeCoverageSupportOptions() if $coverageSupport && $dir ne "ANGLE";<br /> $result = buildXCodeProject($dir, $clean, @local_options, @ARGV);<br /> } elsif (isAppleWinWebKit()) {<br /> if ($dir eq "WebKit") {<br /> $result = buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean);<br /> }<br /> }<br /> # Various build* calls above may change the CWD.<br /> chdirWebKit();<br /> if (exitStatus($result)) {<br /> my $scriptDir = relativeScriptsDir();<br /> if (usingVisualStudioExpress()) {<br /> # Visual Studio Express is so lame it can't stdout build failures.<br /> # So we find its logs and dump them to the console ourselves.<br /> system(File::Spec->catfile($scriptDir, "print-vse-failure-logs"));<br /> }<br /> if (isAppleWinWebKit()) {<br /> print "/n/n===== BUILD FAILED ======/n/n";<br /> print "Please ensure you have run $scriptDir/update-webkit to install dependencies./n/n";<br /> my $baseProductDir = baseProductDir();<br /> print "You can view build errors by checking the BuildLog.htm files located at:/n$baseProductDir/obj//./n";<br /> }<br /> exit exitStatus($result);<br /> }<br />}
在cygwin+vs的環境下執行的是:buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean),buildVisualStudioProject的代碼如下(在webkitdirs.pm的1205行):
sub buildVisualStudioProject<br />{<br /> my ($project, $clean) = @_;<br /> setupCygwinEnv();<br /> my $config = configurationForVisualStudio();<br /> dieIfWindowsPlatformSDKNotInstalled() if $willUseVCExpressWhenBuilding;<br /> chomp($project = `cygpath -w "$project"`) if isCygwin();<br /> my $action = "/build";<br /> if ($clean) {<br /> $action = "/clean";<br /> }<br /> my @command = ($vcBuildPath, $project, $action, $config);<br /> print join(" ", @command), "/n";<br /> return system @command;<br />}
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下面檔案的編譯順序和規則等。