The code imports required modules and defines constants, then uses the buildDylib
function to compile a dynamic library, extract environment variables, and recompile if necessary, assuming the library is written in C, C++, or Objective-C.
Or in two sentences:
The code imports necessary modules and defines constants for a build process. The buildDylib
function compiles a dynamic library, extracts environment variables, and recompiles if necessary, assuming the library is written in C, C++, or Objective-C.
npm run import -- "build dylib"
const fs = require('fs')
const path = require('path')
const { interpret } = require('../Core')
const { safeurl } = importer.import("domain cache tools")
const parse = importer.import("shell parse")
const BUILD_DIRECTORY = path.join(__dirname, '../.build')
const SCAN_ENVIRONMENT = /([A-Z_])\s*[\:-=]+\s*(.*?)\s*(\n|$)/g
function buildDylib(code, pathToCode, ctx) {
if (!fs.existsSync(BUILD_DIRECTORY)) {
fs.mkdirSync(BUILD_DIRECTORY)
}
const codeCell = interpret(pathToCode)
// TODO: compare file times for dylib module recompile
let libName = safeurl(codeCell.questions[0])
let libPath = path.join(BUILD_DIRECTORY, libName + (codeCell.language == 'cpp' ? '.cpp' : '.c'))
if (!fs.existsSync(libPath)
|| fs.statSync(codeCell.filename).mtime > fs.statSync(libPath).mtime
) {
fs.writeFileSync(libPath, codeCell.source.join(''))
}
let env = {}
let match;
while ((match = SCAN_ENVIRONMENT.exec(codeCell.markdown.join(''))) !== null) {
env[match[1]] = match[2]
}
if(codeCell.language == 'cpp') {
env['CXX'] = parse(process.env.CXX) || ['clang++']
env['STD'] = parse(process.env.STD) || ['-std=c++17', '-stdlib=libc++']
} else {
env['CXX'] = parse(process.env.CXX) || ['clang']
}
// TODO: recompile dylib
let objPath = path.join(BUILD_DIRECTORY, libName + '.o')
if (!fs.existsSync(objPath)
|| fs.statSync(libPath).mtime > fs.statSync(objPath).mtime
) {
const { spawnSync } = require('child_process')
let mods = []
if(codeCell.language == 'objective-c') {
mods = ['-x', 'objective-c', '-fno-objc-arc']
}
if(codeCell.source.join('').match('@import')) {
mods = ['-fmodules'].concat(mods)
}
let cflags = []
if(env['PKG_CONFIG']) {
let result = spawnSync('pkg-config', ['--cflags'].concat(parse(env['PKG_CONFIG'])))
cflags = parse(result.stdout.toString())
}
let args = ['-c', libPath, '-o', objPath]
// TODO:
//export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/opt/homebrew/Cellar/mono/6.12.0.206/lib/pkgconfig"
spawnSync(env['CXX'][0], env['CXX'].slice(1).concat(mods).concat(cflags).concat(args), { stdio: [0, 1, 2], env })
}
let modPath = path.join(BUILD_DIRECTORY, libName + '.dylib')
if (!fs.existsSync(modPath)
|| fs.statSync(objPath).mtime > fs.statSync(modPath).mtime
) {
const { spawnSync } = require('child_process')
let libs = []
if(env['PKG_CONFIG']) {
let result = spawnSync('pkg-config', ['--libs'].concat(parse(env['PKG_CONFIG'])))
libs = parse(result.stdout.toString())
}
let mods = []
if(env['CXX'].match('clang')) {
mods = ['-dynamiclib', '-rdynamic']
}
let objs = [objPath]
let args = ['-o', modPath]
spawnSync(env['CXX'][0], objs.concat(mods).concat(libs).concat(args), { stdio: [0, 1, 2] })
}
}
module.exports = buildDylib
const path = require('path');
const { interpret, safeurl } = require('./core');
const { parse } = require('./shell-parse');
const BUILD_DIRECTORY = path.join(__dirname, '../.build');
const SCAN_ENVIRONMENT = /([A-Z_])\s*[\:-=]+\s*(.*?)\s*(\n|$)/g;
/**
* Build a dynamic library from the given code.
*
* @param {object} code - The code to build.
* @param {string} pathToCode - The path to the code file.
* @param {object} ctx - The build context.
*/
function buildDylib(code, pathToCode, ctx) {
// Create the build directory if it does not exist.
if (!fs.existsSync(BUILD_DIRECTORY)) {
fs.mkdirSync(BUILD_DIRECTORY);
}
// Interpret the code and get the code cell.
const codeCell = interpret(pathToCode);
// Get the library name and path.
const libName = safeurl(codeCell.questions[0]);
const libPath = path.join(BUILD_DIRECTORY, libName + (codeCell.language == 'cpp'? '.cpp' : '.c'));
// Check if the library source file needs to be written.
if (!fs.existsSync(libPath) || fs.statSync(codeCell.filename).mtime > fs.statSync(libPath).mtime) {
// Write the library source file.
fs.writeFileSync(libPath, codeCell.source.join(''));
}
// Initialize the environment object.
const env = {};
// Parse the environment variables from the code cell's markdown.
let match;
while ((match = SCAN_ENVIRONMENT.exec(codeCell.markdown.join('')))!== null) {
env[match[1]] = match[2];
}
// Parse the CXX and STD environment variables.
if (codeCell.language == 'cpp') {
env['CXX'] = parse(process.env.CXX) || ['clang++'];
env['STD'] = parse(process.env.STD) || ['-std=c++17', '-stdlib=libc++'];
} else {
env['CXX'] = parse(process.env.CXX) || ['clang'];
}
// Build the library object file.
const objPath = path.join(BUILD_DIRECTORY, libName + '.o');
if (!fs.existsSync(objPath) || fs.statSync(libPath).mtime > fs.statSync(objPath).mtime) {
// Get the compiler and flags.
const { spawnSync } = require('child_process');
let mods = [];
if (codeCell.language == 'objective-c') {
mods = ['-x', 'objective-c', '-fno-objc-arc'];
}
if (codeCell.source.join('').match('@import')) {
mods = ['-fmodules'].concat(mods);
}
let cflags = [];
if (env['PKG_CONFIG']) {
let result = spawnSync('pkg-config', ['--cflags'].concat(parse(env['PKG_CONFIG'])));
cflags = parse(result.stdout.toString());
}
let args = ['-c', libPath, '-o', objPath];
try {
spawnSync(env['CXX'][0], env['CXX'].slice(1).concat(mods).concat(cflags).concat(args), { stdio: [0, 1, 2], env });
} catch (error) {
console.error(`Error building library object file: ${error}`);
return;
}
}
// Build the dynamic library.
const modPath = path.join(BUILD_DIRECTORY, libName + '.dylib');
if (!fs.existsSync(modPath) || fs.statSync(objPath).mtime > fs.statSync(modPath).mtime) {
// Get the linker flags.
let libs = [];
if (env['PKG_CONFIG']) {
let result = spawnSync('pkg-config', ['--libs'].concat(parse(env['PKG_CONFIG'])));
libs = parse(result.stdout.toString());
}
let mods = [];
if (env['CXX'].match('clang')) {
mods = ['-dynamiclib', '-rdynamic'];
}
let objs = [objPath];
let args = ['-o', modPath];
try {
spawnSync(env['CXX'][0], objs.concat(mods).concat(libs).concat(args), { stdio: [0, 1, 2] });
} catch (error) {
console.error(`Error building dynamic library: ${error}`);
return;
}
}
}
module.exports = buildDylib;
Code Breakdown
The code begins by importing required modules and defining constants:
fs
(File System) and path
are imported for file system operations.interpret
is imported from the ../Core
module.safeurl
is imported from the domain cache tools
module.parse
is imported from the shell parse
module.BUILD_DIRECTORY
is set to the path of the build directory.SCAN_ENVIRONMENT
is a regular expression to scan for environment variables.The buildDylib
function takes three arguments: code
, pathToCode
, and ctx
. It performs the following operations:
interpret
function, and the resulting codeCell
object is created.SCAN_ENVIRONMENT
.CXX
and STD
variables are set to default values.The code appears to be a part of a build process for a dynamic library (dylib). It compiles the library code, extracts environment variables, and recompiles the library if necessary. The code assumes that the library is written in C, C++, or Objective-C.