forked from electron/rebuild
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclang-fetcher.ts
123 lines (105 loc) · 4.83 KB
/
clang-fetcher.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import * as cp from 'child_process';
import debug from 'debug';
import * as fs from 'fs-extra';
import * as path from 'path';
import semver from 'semver';
import * as tar from 'tar';
import * as zlib from 'zlib';
import { ELECTRON_GYP_DIR } from './constants';
import { fetch } from './fetcher';
import { downloadLinuxSysroot } from './sysroot-fetcher';
const d = debug('electron-rebuild');
const CDS_URL = 'https://commondatastorage.googleapis.com/chromium-browser-clang';
function getPlatformUrlPrefix(hostOS: string) {
const prefixMap = {
'linux': 'Linux_x64',
'darwin': 'Mac',
'win32': 'Win',
}
return CDS_URL + '/' + prefixMap[hostOS] + '/'
}
function getClangDownloadURL(packageFile: string, packageVersion: string, hostOS: string) {
const cdsFile = `${packageFile}-${packageVersion}.tgz`;
return getPlatformUrlPrefix(hostOS) + cdsFile;
}
function getSDKRoot(): string {
if (process.env.SDKROOT) return process.env.SDKROOT;
const output = cp.execFileSync('xcrun', ['--sdk', 'macosx', '--show-sdk-path']);
return output.toString().trim();
}
export async function getClangEnvironmentVars(electronVersion: string, targetArch: string): Promise<{ env: Record<string, string>; args: string[] }> {
const clangDownloadDir = await downloadClangVersion(electronVersion);
const clangDir = path.resolve(clangDownloadDir, 'bin');
const cxxflags = [];
const clangArgs: string[] = [];
if (process.platform === 'darwin') {
clangArgs.push('-isysroot', getSDKRoot());
}
if (semver.major(electronVersion) >= 20) {
cxxflags.push('-std=c++17');
}
const gypArgs = [];
if (process.platform === 'win32') {
console.log(fs.readdirSync(clangDir));
gypArgs.push(`/p:CLToolExe=clang-cl.exe`, `/p:CLToolPath=${clangDir}`);
}
if (process.platform === 'linux') {
const sysrootPath = await downloadLinuxSysroot(electronVersion, targetArch);
clangArgs.push('--sysroot', sysrootPath);
}
return {
env: {
CC: `"${path.resolve(clangDir, 'clang')}" ${clangArgs.join(' ')}`,
CXX: `"${path.resolve(clangDir, 'clang++')}" ${clangArgs.join(' ')}`,
CXXFLAGS: `${cxxflags.join(' ')}`
},
args: gypArgs,
}
}
function clangVersionFromRevision(update: string): string | null {
const regex = /CLANG_REVISION = '([^']+)'\nCLANG_SUB_REVISION = (\d+)\n/g;
const clangVersionMatch = regex.exec(update);
if (!clangVersionMatch) return null;
const [,clangVersion, clangSubRevision] = clangVersionMatch;
return `${clangVersion}-${clangSubRevision}`;
}
function clangVersionFromSVN(update: string): string | null {
const regex = /CLANG_REVISION = '([^']+)'\nCLANG_SVN_REVISION = '([^']+)'\nCLANG_SUB_REVISION = (\d+)\n/g;
const clangVersionMatch = regex.exec(update);
if (!clangVersionMatch) return null;
const [,clangVersion, clangSvn, clangSubRevision] = clangVersionMatch;
return `${clangSvn}-${clangVersion.substr(0, 8)}-${clangSubRevision}`;
}
async function downloadClangVersion(electronVersion: string) {
d('fetching clang for Electron:', electronVersion);
const clangDirPath = path.resolve(ELECTRON_GYP_DIR, `${electronVersion}-clang`);
if (await fs.pathExists(path.resolve(clangDirPath, 'bin', 'clang'))) return clangDirPath;
if (!await fs.pathExists(ELECTRON_GYP_DIR)) await fs.mkdirp(ELECTRON_GYP_DIR);
const electronDeps = await fetch(`https://raw.githubusercontent.com/electron/electron/v${electronVersion}/DEPS`, 'text');
const chromiumRevisionExtractor = /'chromium_version':\n\s+'([^']+)/g;
const chromiumRevisionMatch = chromiumRevisionExtractor.exec(electronDeps);
if (!chromiumRevisionMatch) throw new Error('Failed to determine Chromium revision for given Electron version');
const chromiumRevision = chromiumRevisionMatch[1];
d('fetching clang for Chromium:', chromiumRevision)
const base64ClangUpdate = await fetch(`https://chromium.googlesource.com/chromium/src.git/+/${chromiumRevision}/tools/clang/scripts/update.py?format=TEXT`, 'text');
const clangUpdate = Buffer.from(base64ClangUpdate, 'base64').toString('utf8');
const clangVersionString = clangVersionFromRevision(clangUpdate) || clangVersionFromSVN(clangUpdate);
if (!clangVersionString) throw new Error('Failed to determine Clang revision from Electron version');
d('fetching clang:', clangVersionString);
const clangDownloadURL = getClangDownloadURL('clang', clangVersionString, process.platform);
const contents = await fetch(clangDownloadURL, 'buffer');
d('deflating clang');
zlib.deflateSync(contents);
const tarPath = path.resolve(ELECTRON_GYP_DIR, `${electronVersion}-clang.tar`);
if (await fs.pathExists(tarPath)) await fs.remove(tarPath)
await fs.writeFile(tarPath, Buffer.from(contents));
await fs.mkdirp(clangDirPath);
d('tar running on clang');
await tar.x({
file: tarPath,
cwd: clangDirPath,
});
await fs.remove(tarPath);
d('cleaning up clang tar file');
return clangDirPath;
}