112 lines
5.1 KiB
JavaScript
112 lines
5.1 KiB
JavaScript
|
|
import cp from 'node:child_process';
|
||
|
|
import debug from 'debug';
|
||
|
|
import fs from 'graceful-fs';
|
||
|
|
import path from 'node:path';
|
||
|
|
import * as tar from 'tar';
|
||
|
|
import zlib from 'node:zlib';
|
||
|
|
import { ELECTRON_GYP_DIR } from './constants.js';
|
||
|
|
import { fetch } from './fetcher.js';
|
||
|
|
import { downloadLinuxSysroot } from './sysroot-fetcher.js';
|
||
|
|
import { promisifiedGracefulFs } from './promisifiedGracefulFs.js';
|
||
|
|
const d = debug('electron-rebuild');
|
||
|
|
const CDS_URL = 'https://commondatastorage.googleapis.com/chromium-browser-clang';
|
||
|
|
function getPlatformUrlPrefix(hostOS, hostArch) {
|
||
|
|
const prefixMap = {
|
||
|
|
'linux': 'Linux_x64',
|
||
|
|
'darwin': 'Mac',
|
||
|
|
'win32': 'Win',
|
||
|
|
};
|
||
|
|
let prefix = prefixMap[hostOS];
|
||
|
|
if (prefix === 'Mac' && hostArch === 'arm64') {
|
||
|
|
prefix = 'Mac_arm64';
|
||
|
|
}
|
||
|
|
return CDS_URL + '/' + prefix + '/';
|
||
|
|
}
|
||
|
|
function getClangDownloadURL(packageFile, packageVersion, hostOS, hostArch) {
|
||
|
|
const cdsFile = `${packageFile}-${packageVersion}.tgz`;
|
||
|
|
return getPlatformUrlPrefix(hostOS, hostArch) + cdsFile;
|
||
|
|
}
|
||
|
|
function getSDKRoot() {
|
||
|
|
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, targetArch) {
|
||
|
|
const clangDownloadDir = await downloadClangVersion(electronVersion);
|
||
|
|
const clangDir = path.resolve(clangDownloadDir, 'bin');
|
||
|
|
const clangArgs = [];
|
||
|
|
if (process.platform === 'darwin') {
|
||
|
|
clangArgs.push('-isysroot', getSDKRoot());
|
||
|
|
}
|
||
|
|
const gypArgs = [];
|
||
|
|
if (process.platform === 'win32') {
|
||
|
|
console.log(await promisifiedGracefulFs.readdir(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(' ')}`,
|
||
|
|
},
|
||
|
|
args: gypArgs,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
function clangVersionFromRevision(update) {
|
||
|
|
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) {
|
||
|
|
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) {
|
||
|
|
d('fetching clang for Electron:', electronVersion);
|
||
|
|
const clangDirPath = path.resolve(ELECTRON_GYP_DIR, `${electronVersion}-clang`);
|
||
|
|
if (fs.existsSync(path.resolve(clangDirPath, 'bin', 'clang')))
|
||
|
|
return clangDirPath;
|
||
|
|
await fs.promises.mkdir(ELECTRON_GYP_DIR, { recursive: true });
|
||
|
|
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, process.arch);
|
||
|
|
const contents = await fetch(clangDownloadURL, 'buffer');
|
||
|
|
d('deflating clang');
|
||
|
|
zlib.deflateSync(contents);
|
||
|
|
const tarPath = path.resolve(ELECTRON_GYP_DIR, `${electronVersion}-clang.tar`);
|
||
|
|
if (fs.existsSync(tarPath))
|
||
|
|
await fs.promises.rm(tarPath, { recursive: true, force: true });
|
||
|
|
await promisifiedGracefulFs.writeFile(tarPath, Buffer.from(contents));
|
||
|
|
await fs.promises.mkdir(clangDirPath, { recursive: true });
|
||
|
|
d('tar running on clang');
|
||
|
|
await tar.x({
|
||
|
|
file: tarPath,
|
||
|
|
cwd: clangDirPath,
|
||
|
|
});
|
||
|
|
await fs.promises.rm(tarPath, { recursive: true, force: true });
|
||
|
|
d('cleaning up clang tar file');
|
||
|
|
return clangDirPath;
|
||
|
|
}
|
||
|
|
//# sourceMappingURL=clang-fetcher.js.map
|