Skip to content

Commit 17c169a

Browse files
authored
Refactor package dependencies generators (microsoft#157845)
1 parent 7b38f89 commit 17c169a

18 files changed

+280
-366
lines changed

build/gulpfile.vscode.linux.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ const util = require('./lib/util');
1515
const task = require('./lib/task');
1616
const packageJson = require('../package.json');
1717
const product = require('../product.json');
18-
const rpmDependenciesGenerator = require('./linux/rpm/dependencies-generator');
19-
const debianDependenciesGenerator = require('./linux/debian/dependencies-generator');
18+
const dependenciesGenerator = require('./linux/dependencies-generator');
2019
const sysrootInstaller = require('./linux/debian/install-sysroot');
2120
const debianRecommendedDependencies = require('./linux/debian/dep-lists').recommendedDeps;
2221
const path = require('path');
@@ -25,6 +24,9 @@ const commit = util.getVersion(root);
2524

2625
const linuxPackageRevision = Math.floor(new Date().getTime() / 1000);
2726

27+
/**
28+
* @param {string} arch
29+
*/
2830
function getDebPackageArch(arch) {
2931
return { x64: 'amd64', armhf: 'armhf', arm64: 'arm64' }[arch];
3032
}
@@ -80,7 +82,7 @@ function prepareDebPackage(arch) {
8082
async function () {
8183
const that = this;
8284
const sysroot = await sysrootInstaller.getSysroot(debArch);
83-
const dependencies = debianDependenciesGenerator.getDependencies(binaryDir, product.applicationName, debArch, sysroot);
85+
const dependencies = dependenciesGenerator.getDependencies('deb', binaryDir, product.applicationName, debArch, sysroot);
8486
gulp.src('resources/linux/debian/control.template', { base: '.' })
8587
.pipe(replace('@@NAME@@', product.applicationName))
8688
.pipe(replace('@@VERSION@@', packageJson.version + '-' + linuxPackageRevision))
@@ -183,7 +185,7 @@ function prepareRpmPackage(arch) {
183185
const code = gulp.src(binaryDir + '/**/*', { base: binaryDir })
184186
.pipe(rename(function (p) { p.dirname = 'BUILD/usr/share/' + product.applicationName + '/' + p.dirname; }));
185187

186-
const dependencies = rpmDependenciesGenerator.getDependencies(binaryDir, product.applicationName, rpmArch);
188+
const dependencies = dependenciesGenerator.getDependencies('rpm', binaryDir, product.applicationName, rpmArch);
187189
const spec = gulp.src('resources/linux/rpm/code.spec.template', { base: '.' })
188190
.pipe(replace('@@NAME@@', product.applicationName))
189191
.pipe(replace('@@NAME_LONG@@', product.nameLong))
Lines changed: 7 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,23 @@
1+
"use strict";
12
/*---------------------------------------------------------------------------------------------
23
* Copyright (c) Microsoft Corporation. All rights reserved.
34
* Licensed under the MIT License. See License.txt in the project root for license information.
45
*--------------------------------------------------------------------------------------------*/
5-
'use strict';
66
Object.defineProperty(exports, "__esModule", { value: true });
7-
exports.getDependencies = void 0;
7+
exports.generatePackageDeps = void 0;
88
const child_process_1 = require("child_process");
99
const fs_1 = require("fs");
1010
const os_1 = require("os");
1111
const path = require("path");
12-
const dep_lists_1 = require("./dep-lists");
1312
const manifests = require("../../../cgmanifest.json");
14-
// A flag that can easily be toggled.
15-
// Make sure to compile the build directory after toggling the value.
16-
// If false, we warn about new dependencies if they show up
17-
// while running the Debian prepare package task for a release.
18-
// If true, we fail the build if there are new dependencies found during that task.
19-
// The reference dependencies, which one has to update when the new dependencies
20-
// are valid, are in dep-lists.ts
21-
const FAIL_BUILD_FOR_NEW_DEPENDENCIES = true;
22-
function getDependencies(buildDir, applicationName, arch, sysroot) {
23-
// Get the files for which we want to find dependencies.
24-
const nativeModulesPath = path.join(buildDir, 'resources', 'app', 'node_modules.asar.unpacked');
25-
const findResult = (0, child_process_1.spawnSync)('find', [nativeModulesPath, '-name', '*.node']);
26-
if (findResult.status) {
27-
console.error('Error finding files:');
28-
console.error(findResult.stderr.toString());
29-
return [];
30-
}
31-
const files = findResult.stdout.toString().trimEnd().split('\n');
32-
const appPath = path.join(buildDir, applicationName);
33-
files.push(appPath);
34-
// Add chrome sandbox and crashpad handler.
35-
files.push(path.join(buildDir, 'chrome-sandbox'));
36-
files.push(path.join(buildDir, 'chrome_crashpad_handler'));
37-
// Generate the dependencies.
38-
const dependencies = files.map((file) => calculatePackageDeps(file, arch, sysroot));
39-
// Add additional dependencies.
13+
const dep_lists_1 = require("./dep-lists");
14+
function generatePackageDeps(files, arch, sysroot) {
15+
const dependencies = files.map(file => calculatePackageDeps(file, arch, sysroot));
4016
const additionalDepsSet = new Set(dep_lists_1.additionalDeps);
4117
dependencies.push(additionalDepsSet);
42-
// Merge all the dependencies.
43-
const mergedDependencies = mergePackageDeps(dependencies);
44-
let sortedDependencies = [];
45-
for (const dependency of mergedDependencies) {
46-
sortedDependencies.push(dependency);
47-
}
48-
sortedDependencies.sort();
49-
// Exclude bundled dependencies
50-
sortedDependencies = sortedDependencies.filter(dependency => {
51-
return !dep_lists_1.bundledDeps.some(bundledDep => dependency.startsWith(bundledDep));
52-
});
53-
const referenceGeneratedDeps = dep_lists_1.referenceGeneratedDepsByArch[arch];
54-
if (JSON.stringify(sortedDependencies) !== JSON.stringify(referenceGeneratedDeps)) {
55-
const failMessage = 'The dependencies list has changed.'
56-
+ '\nOld:\n' + referenceGeneratedDeps.join('\n')
57-
+ '\nNew:\n' + sortedDependencies.join('\n');
58-
if (FAIL_BUILD_FOR_NEW_DEPENDENCIES) {
59-
throw new Error(failMessage);
60-
}
61-
else {
62-
console.warn(failMessage);
63-
}
64-
}
65-
return sortedDependencies;
18+
return dependencies;
6619
}
67-
exports.getDependencies = getDependencies;
20+
exports.generatePackageDeps = generatePackageDeps;
6821
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/calculate_package_deps.py.
6922
function calculatePackageDeps(binaryPath, arch, sysroot) {
7023
try {
@@ -97,8 +50,6 @@ function calculatePackageDeps(binaryPath, arch, sysroot) {
9750
case 'arm64':
9851
cmd.push(`-l${sysroot}/usr/lib/aarch64-linux-gnu`, `-l${sysroot}/lib/aarch64-linux-gnu`);
9952
break;
100-
default:
101-
throw new Error('Unsupported architecture ' + arch);
10253
}
10354
cmd.push(`-l${sysroot}/usr/lib`);
10455
cmd.push('-O', '-e', path.resolve(binaryPath));
@@ -117,17 +68,3 @@ function calculatePackageDeps(binaryPath, arch, sysroot) {
11768
const requires = new Set(depsStr.split(', ').sort());
11869
return requires;
11970
}
120-
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/rpm/merge_package_deps.py.
121-
function mergePackageDeps(inputDeps) {
122-
// For now, see if directly appending the dependencies helps.
123-
const requires = new Set();
124-
for (const depSet of inputDeps) {
125-
for (const dep of depSet) {
126-
const trimmedDependency = dep.trim();
127-
if (trimmedDependency.length && !trimmedDependency.startsWith('#')) {
128-
requires.add(trimmedDependency);
129-
}
130-
}
131-
}
132-
return requires;
133-
}

build/linux/debian/calculate-deps.ts

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import { spawnSync } from 'child_process';
7+
import { constants, statSync } from 'fs';
8+
import { tmpdir } from 'os';
9+
import path = require('path');
10+
import * as manifests from '../../../cgmanifest.json';
11+
import { additionalDeps } from './dep-lists';
12+
import { DebianArchString } from './types';
13+
14+
export function generatePackageDeps(files: string[], arch: DebianArchString, sysroot: string): Set<string>[] {
15+
const dependencies: Set<string>[] = files.map(file => calculatePackageDeps(file, arch, sysroot));
16+
const additionalDepsSet = new Set(additionalDeps);
17+
dependencies.push(additionalDepsSet);
18+
return dependencies;
19+
}
20+
21+
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/calculate_package_deps.py.
22+
function calculatePackageDeps(binaryPath: string, arch: DebianArchString, sysroot: string): Set<string> {
23+
try {
24+
if (!(statSync(binaryPath).mode & constants.S_IXUSR)) {
25+
throw new Error(`Binary ${binaryPath} needs to have an executable bit set.`);
26+
}
27+
} catch (e) {
28+
// The package might not exist. Don't re-throw the error here.
29+
console.error('Tried to stat ' + binaryPath + ' but failed.');
30+
}
31+
32+
// Get the Chromium dpkg-shlibdeps file.
33+
const chromiumManifest = manifests.registrations.filter(registration => {
34+
return registration.component.type === 'git' && registration.component.git!.name === 'chromium';
35+
});
36+
const dpkgShlibdepsUrl = `https://raw.githubusercontent.com/chromium/chromium/${chromiumManifest[0].version}/third_party/dpkg-shlibdeps/dpkg-shlibdeps.pl`;
37+
const dpkgShlibdepsScriptLocation = `${tmpdir()}/dpkg-shlibdeps.pl`;
38+
const result = spawnSync('curl', [dpkgShlibdepsUrl, '-o', dpkgShlibdepsScriptLocation]);
39+
if (result.status !== 0) {
40+
throw new Error('Cannot retrieve dpkg-shlibdeps. Stderr:\n' + result.stderr);
41+
}
42+
const cmd = [dpkgShlibdepsScriptLocation, '--ignore-weak-undefined'];
43+
switch (arch) {
44+
case 'amd64':
45+
cmd.push(`-l${sysroot}/usr/lib/x86_64-linux-gnu`,
46+
`-l${sysroot}/lib/x86_64-linux-gnu`);
47+
break;
48+
case 'armhf':
49+
cmd.push(`-l${sysroot}/usr/lib/arm-linux-gnueabihf`,
50+
`-l${sysroot}/lib/arm-linux-gnueabihf`);
51+
break;
52+
case 'arm64':
53+
cmd.push(`-l${sysroot}/usr/lib/aarch64-linux-gnu`,
54+
`-l${sysroot}/lib/aarch64-linux-gnu`);
55+
break;
56+
}
57+
cmd.push(`-l${sysroot}/usr/lib`);
58+
cmd.push('-O', '-e', path.resolve(binaryPath));
59+
60+
const dpkgShlibdepsResult = spawnSync('perl', cmd, { cwd: sysroot });
61+
if (dpkgShlibdepsResult.status !== 0) {
62+
throw new Error(`dpkg-shlibdeps failed with exit code ${dpkgShlibdepsResult.status}. stderr:\n${dpkgShlibdepsResult.stderr} `);
63+
}
64+
65+
const shlibsDependsPrefix = 'shlibs:Depends=';
66+
const requiresList = dpkgShlibdepsResult.stdout.toString('utf-8').trimEnd().split('\n');
67+
let depsStr = '';
68+
for (const line of requiresList) {
69+
if (line.startsWith(shlibsDependsPrefix)) {
70+
depsStr = line.substring(shlibsDependsPrefix.length);
71+
}
72+
}
73+
const requires = new Set(depsStr.split(', ').sort());
74+
return requires;
75+
}

build/linux/debian/dep-lists.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Licensed under the MIT License. See License.txt in the project root for license information.
55
*--------------------------------------------------------------------------------------------*/
66
Object.defineProperty(exports, "__esModule", { value: true });
7-
exports.referenceGeneratedDepsByArch = exports.bundledDeps = exports.recommendedDeps = exports.additionalDeps = void 0;
7+
exports.referenceGeneratedDepsByArch = exports.recommendedDeps = exports.additionalDeps = void 0;
88
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/additional_deps
99
// Additional dependencies not in the dpkg-shlibdeps output.
1010
exports.additionalDeps = [
@@ -20,18 +20,6 @@ exports.additionalDeps = [
2020
exports.recommendedDeps = [
2121
'libvulkan1' // Move to additionalDeps once support for Trusty and Jessie are dropped.
2222
];
23-
// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80
24-
// and the Linux Archive build
25-
// Shared library dependencies that we already bundle.
26-
exports.bundledDeps = [
27-
'libEGL.so',
28-
'libGLESv2.so',
29-
'libvulkan.so.1',
30-
'swiftshader_libEGL.so',
31-
'swiftshader_libGLESv2.so',
32-
'libvk_swiftshader.so',
33-
'libffmpeg.so'
34-
];
3523
exports.referenceGeneratedDepsByArch = {
3624
'amd64': [
3725
'ca-certificates',

build/linux/debian/dep-lists.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,6 @@ export const recommendedDeps = [
2020
'libvulkan1' // Move to additionalDeps once support for Trusty and Jessie are dropped.
2121
];
2222

23-
// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80
24-
// and the Linux Archive build
25-
// Shared library dependencies that we already bundle.
26-
export const bundledDeps = [
27-
'libEGL.so',
28-
'libGLESv2.so',
29-
'libvulkan.so.1',
30-
'swiftshader_libEGL.so',
31-
'swiftshader_libGLESv2.so',
32-
'libvk_swiftshader.so',
33-
'libffmpeg.so'
34-
];
35-
3623
export const referenceGeneratedDepsByArch = {
3724
'amd64': [
3825
'ca-certificates',

0 commit comments

Comments
 (0)