Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,28 @@ jobs:
with:
node-version: '22.x'

- name: Install sysroot
if: runner.os == 'Linux'
run: |
sudo apt-get update -qq
sudo apt-get install -y gcc-10 g++-10
SYSROOT_PATH=$(node scripts/linux/install-sysroot.js x64 | grep "SYSROOT_PATH=" | cut -d= -f2)
echo "SYSROOT_PATH=$SYSROOT_PATH" >> $GITHUB_ENV
echo "Sysroot path set to: $SYSROOT_PATH"
echo "CC=gcc-10" >> $GITHUB_ENV
echo "CXX=g++-10" >> $GITHUB_ENV

- name: Install dependencies and build
run: npm ci

- name: Verify GLIBC requirements
if: runner.os == 'Linux'
run: |
EXPECTED_GLIBC_VERSION="2.28" \
EXPECTED_GLIBCXX_VERSION="3.4.25" \
SEARCH_PATH="build" \
./scripts/linux/verify-glibc-requirements.sh

- name: Test
run: npm test

Expand Down
56 changes: 56 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
'-lutil'
],
'cflags': ['-Wall', '-O2', '-D_FORTIFY_SOURCE=2'],
'ldflags': [],
'conditions': [
# http://www.gnu.org/software/gnulib/manual/html_node/forkpty.html
# One some systems (at least including Cygwin, Interix,
Expand All @@ -88,6 +89,61 @@
'libraries!': [
'-lutil'
]
}],
['OS=="linux"', {
'variables': {
'sysroot%': '<!(node -p "process.env.SYSROOT_PATH || \'\'")',
'target_arch%': '<!(node -p "process.env.npm_config_arch || process.arch")',
},
'conditions': [
['sysroot!=""', {
'variables': {
'gcc_include%': '<!(${CXX:-g++} -print-file-name=include)',
},
'conditions': [
['target_arch=="x64"', {
'cflags': [
'--sysroot=<(sysroot)',
'-nostdinc',
'-isystem<(gcc_include)',
'-isystem<(sysroot)/usr/include',
'-isystem<(sysroot)/usr/include/x86_64-linux-gnu'
],
'cflags_cc': [
'-nostdinc++',
'-isystem<(sysroot)/../include/c++/10.5.0',
'-isystem<(sysroot)/../include/c++/10.5.0/x86_64-linux-gnu',
'-isystem<(sysroot)/../include/c++/10.5.0/backward'
],
'ldflags': [
'--sysroot=<(sysroot)',
'-L<(sysroot)/lib',
'-L<(sysroot)/usr/lib'
],
}],
['target_arch=="arm64"', {
'cflags': [
'--sysroot=<(sysroot)',
'-nostdinc',
'-isystem<(gcc_include)',
'-isystem<(sysroot)/usr/include',
'-isystem<(sysroot)/usr/include/aarch64-linux-gnu'
],
'cflags_cc': [
'-nostdinc++',
'-isystem<(sysroot)/../include/c++/10.5.0',
'-isystem<(sysroot)/../include/c++/10.5.0/aarch64-linux-gnu',
'-isystem<(sysroot)/../include/c++/10.5.0/backward'
],
'ldflags': [
'--sysroot=<(sysroot)',
'-L<(sysroot)/lib',
'-L<(sysroot)/usr/lib'
],
}]
]
}]
]
}]
]
}
Expand Down
24 changes: 22 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions pipelines/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,23 @@ steps:
addToPath: true
displayName: 'Use latest Python 3.x'

- bash: |
if [ "$(uname)" = "Linux" ]; then
sudo apt-get update -qq
sudo apt-get install -y gcc-10 g++-10
SYSROOT_PATH=$(node scripts/linux/install-sysroot.js ${{ parameters.arch }} | grep "SYSROOT_PATH=" | cut -d= -f2)
echo "##vso[task.setvariable variable=SYSROOT_PATH]$SYSROOT_PATH"
echo "##vso[task.setvariable variable=CC]gcc-10"
echo "##vso[task.setvariable variable=CXX]g++-10"
echo "Sysroot path set to: $SYSROOT_PATH"
fi
displayName: 'Install sysroot (Linux only)'

- script: npm ci
displayName: 'Install dependencies'
env:
ARCH: ${{ parameters.arch }}
npm_config_arch: ${{ parameters.arch }}
SYSROOT_PATH: $(SYSROOT_PATH)
CC: $(CC)
CXX: $(CXX)
6 changes: 2 additions & 4 deletions pipelines/prebuilds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,6 @@ extends:
cp -r $(Build.ArtifactStagingDirectory)/win32-arm64 $(Build.ArtifactStagingDirectory)/prebuilds/
cp -r $(Build.ArtifactStagingDirectory)/darwin-x64 $(Build.ArtifactStagingDirectory)/prebuilds/
cp -r $(Build.ArtifactStagingDirectory)/darwin-arm64 $(Build.ArtifactStagingDirectory)/prebuilds/
# Exclude Linux prebuilds for now
# cp -r $(Build.ArtifactStagingDirectory)/linux-x64 $(Build.ArtifactStagingDirectory)/prebuilds/
# cp -r $(Build.ArtifactStagingDirectory)/linux-arm64 $(Build.ArtifactStagingDirectory)/prebuilds/
cp -r $(Build.ArtifactStagingDirectory)/linux-x64 $(Build.ArtifactStagingDirectory)/prebuilds/
cp -r $(Build.ArtifactStagingDirectory)/linux-arm64 $(Build.ArtifactStagingDirectory)/prebuilds/
displayName: 'Create prebuilds archive'
2 changes: 2 additions & 0 deletions scripts/linux/checksums.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
3122af49c493c5c767c2b0772a41119cbdc9803125a705683445b4066dc88b82 x86_64-linux-gnu-glibc-2.28-gcc-10.5.0.tar.gz
3baac81a39b69e0929e4700f4f78f022adefc515010054ec393565657c4fff32 aarch64-linux-gnu-glibc-2.28-gcc-10.5.0.tar.gz
157 changes: 157 additions & 0 deletions scripts/linux/install-sysroot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

const { execSync } = require('child_process');
const { tmpdir } = require('os');
const fs = require('fs');
const path = require('path');
const { createHash } = require('crypto');

const REPO_ROOT = path.join(__dirname, '..', '..');

const ghApiHeaders = {
Accept: 'application/vnd.github.v3+json',
'User-Agent': 'node-pty Build',
};

if (process.env.GITHUB_TOKEN) {
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
}

const ghDownloadHeaders = {
...ghApiHeaders,
Accept: 'application/octet-stream',
};

function getSysrootChecksum(expectedName) {
const checksumPath = path.join(REPO_ROOT, 'scripts', 'linux', 'checksums.txt');
const checksums = fs.readFileSync(checksumPath, 'utf8');
for (const line of checksums.split('\n')) {
const [checksum, name] = line.split(/\s+/);
if (name === expectedName) {
return checksum;
}
}
return undefined;
}

async function fetchUrl(options, retries = 10, retryDelay = 1000) {
try {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
const version = '20250407-330404';
try {
const response = await fetch(`https://api.github.com/repos/Microsoft/vscode-linux-build-agent/releases/tags/v${version}`, {
headers: ghApiHeaders,
signal: controller.signal
});
if (response.ok && (response.status >= 200 && response.status < 300)) {
console.log(`Fetch completed: Status ${response.status}.`);
const contents = Buffer.from(await response.arrayBuffer());
const asset = JSON.parse(contents.toString()).assets.find((a) => a.name === options.assetName);
if (!asset) {
throw new Error(`Could not find asset in release of Microsoft/vscode-linux-build-agent @ ${version}`);
}
console.log(`Found asset ${options.assetName} @ ${asset.url}.`);
const assetResponse = await fetch(asset.url, {
headers: ghDownloadHeaders
});
if (assetResponse.ok && (assetResponse.status >= 200 && assetResponse.status < 300)) {
const assetContents = Buffer.from(await assetResponse.arrayBuffer());
console.log(`Fetched response body buffer: ${assetContents.byteLength} bytes`);
if (options.checksumSha256) {
const actualSHA256Checksum = createHash('sha256').update(assetContents).digest('hex');
if (actualSHA256Checksum !== options.checksumSha256) {
throw new Error(`Checksum mismatch for ${asset.url} (expected ${options.checksumSha256}, actual ${actualSHA256Checksum})`);
}
}
console.log(`Verified SHA256 checksums match for ${asset.url}`);
const tarCommand = `tar -xz -C ${options.dest}`;
execSync(tarCommand, { input: assetContents });
console.log(`Fetch complete!`);
return;
}
throw new Error(`Request ${asset.url} failed with status code: ${assetResponse.status}`);
}
throw new Error(`Request https://api.github.com failed with status code: ${response.status}`);
} finally {
clearTimeout(timeout);
}
} catch (e) {
if (retries > 0) {
console.log(`Fetching failed: ${e}`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
return fetchUrl(options, retries - 1, retryDelay);
}
throw e;
}
}

async function getSysroot(arch) {
let expectedName;
let triple;
const prefix = '-glibc-2.28-gcc-10.5.0';

switch (arch) {
case 'x64':
expectedName = `x86_64-linux-gnu${prefix}.tar.gz`;
triple = 'x86_64-linux-gnu';
break;
case 'arm64':
expectedName = `aarch64-linux-gnu${prefix}.tar.gz`;
triple = 'aarch64-linux-gnu';
break;
default:
throw new Error(`Unsupported architecture: ${arch}`);
}

console.log(`Fetching ${expectedName} for ${triple}`);
const checksumSha256 = getSysrootChecksum(expectedName);
if (!checksumSha256) {
throw new Error(`Could not find checksum for ${expectedName}`);
}

const sysroot = path.join(tmpdir(), `vscode-${arch}-sysroot`);
const stamp = path.join(sysroot, '.stamp');
const result = `${sysroot}/${triple}/${triple}/sysroot`;

if (fs.existsSync(stamp) && fs.readFileSync(stamp).toString() === expectedName) {
console.log(`Sysroot already installed: ${result}`);
return result;
}

console.log(`Installing ${arch} root image: ${sysroot}`);
fs.rmSync(sysroot, { recursive: true, force: true });
fs.mkdirSync(sysroot, { recursive: true });

await fetchUrl({
checksumSha256,
assetName: expectedName,
dest: sysroot
});

fs.writeFileSync(stamp, expectedName);
console.log(`Sysroot installed: ${result}`);
return result;
}

async function main() {
const arch = process.argv[2] || process.env.ARCH || 'x64';
console.log(`Installing sysroot for architecture: ${arch}`);

try {
const sysrootPath = await getSysroot(arch);
console.log(`SYSROOT_PATH=${sysrootPath}`);
} catch (error) {
console.error('Error installing sysroot:', error);
process.exit(1);
}
}

if (require.main === module) {
main();
}

module.exports = { getSysroot };
Loading