llparse-test-fixture
Version:
A test fixture for llparse (and llparse-based modules)
153 lines • 5.56 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.Fixture = exports.ERROR_PAUSE = exports.FixtureResult = void 0;
const node_child_process_1 = require("node:child_process");
const crypto = require("node:crypto");
const fs = require("node:fs");
const os = require("node:os");
const path = require("node:path");
const result_1 = require("./result");
Object.defineProperty(exports, "FixtureResult", { enumerable: true, get: function () { return result_1.FixtureResult; } });
const CLANG = process.env.CLANG || 'clang';
const CFLAGS = process.env.CFLAGS || '';
const WASM = process.env.WASM;
const WASM_CFLAGS = process.env.WASM_CFLAGS || '';
const NATIVE_DIR = path.join(__dirname, '..', 'src', 'native');
const FIXTURE = path.join(NATIVE_DIR, 'fixture.c');
// Just a random value, really
exports.ERROR_PAUSE = 0x7fa73caa;
class Fixture {
options;
constructor(options) {
this.options = {
buildDir: options.buildDir,
clang: options.clang === undefined ? CLANG : options.clang,
wasm: options.wasm === undefined ? WASM : options.wasm,
extra: options.extra || [],
maxParallel: options.maxParallel === undefined ?
os.cpus().length :
options.maxParallel,
};
try {
fs.mkdirSync(this.options.buildDir, { recursive: true });
}
catch (e) {
// no-op
}
}
async build(artifacts, name, options = {}) {
const BUILD_DIR = this.options.buildDir;
const hash = crypto.createHash('sha256');
const c = path.join(BUILD_DIR, name + '.c');
const header = path.join(BUILD_DIR, name + '.h');
hash.update('header');
hash.update(artifacts.header);
await fs.promises.writeFile(header, artifacts.header);
const commonArgs = [
'-g3', '-Os', '-fvisibility=hidden',
'-I', NATIVE_DIR,
'-I', BUILD_DIR,
'-include', header,
FIXTURE,
];
const args = {
c: ['-msse4.2'],
wasm: [
'-msimd128',
'-fno-exceptions',
'-mexec-model=reactor',
'-Wl,-error-limit=0',
'-Wl,--allow-undefined',
'-Wl,--export-dynamic',
'-Wl,--export-table',
'-Wl,--export=malloc',
'-Wl,--export=free',
'-Wl,--no-entry',
],
};
// This is rather lame, but should work
if (CFLAGS) {
for (const flag of CFLAGS.split(/\s+/g)) {
args.c.push(flag);
}
}
if (WASM_CFLAGS) {
for (const flag of WASM_CFLAGS.split(/\s+/g)) {
args.wasm.push(flag);
}
}
hash.update('c');
hash.update(artifacts.c);
await fs.promises.writeFile(c, artifacts.c);
args.c.push(c);
args.wasm.push(c);
for (const extra of this.options.extra) {
commonArgs.push(extra);
}
if (options.extra) {
for (const extra of options.extra) {
commonArgs.push(extra);
}
}
hash.update('common-args');
hash.update(commonArgs.join(' '));
const digest = hash.digest('hex');
const executables = [];
{
const out = path.join(BUILD_DIR, name + '-c.' + digest);
const link = path.join(BUILD_DIR, name + '-c');
if (!fs.existsSync(out)) {
await this.clang(this.options.clang, commonArgs.concat(args.c, '-o', out));
}
try {
await fs.promises.unlink(link);
}
catch (e) {
// no-op
}
await fs.promises.link(out, link);
executables.push(out);
}
if (this.options.wasm) {
const out = path.join(BUILD_DIR, name + '-' + digest + '.wasm');
const link = path.join(BUILD_DIR, name + '.wasm');
if (!fs.existsSync(out)) {
await this.clang(this.options.wasm, commonArgs.concat(args.wasm, '-o', out));
}
try {
await fs.promises.unlink(link);
}
catch (e) {
// no-op
}
await fs.promises.link(out, link);
executables.push(out);
}
return new result_1.FixtureResult(executables, this.options.maxParallel);
}
async clang(bin, args) {
const proc = (0, node_child_process_1.spawn)(bin, args, {
stdio: [null, 'pipe', 'pipe'],
});
const stdout = [];
proc.stdout.on('data', (chunk) => stdout.push(chunk));
const stderr = [];
proc.stderr.on('data', (chunk) => stderr.push(chunk));
const code = await new Promise((resolve) => {
proc.once('exit', exitCode => resolve(exitCode));
});
if (code !== 0) {
if (stdout.length > 0) {
process.stderr.write(Buffer.concat(stdout).toString());
}
if (stderr.length > 0) {
process.stderr.write(Buffer.concat(stderr).toString());
}
const escapedArgs = args.map(arg => JSON.stringify(arg));
throw new Error('clang exit code: ' + code +
`\narguments: ${escapedArgs.join(' ')}`);
}
}
}
exports.Fixture = Fixture;
//# sourceMappingURL=fixture.js.map
;